
给定两个方法A和B,我想交换它们的实现,这样调用A就会执行B.我偶然发现了一些混合的例子(@L_301_0@和example2).我创建了一个带有类的新项目来测试它.
class Swizzle: NSObject{ func method() { print("A"); }}extension Swizzle{ overrIDe class func initialize() { struct Static { static var token: dispatch_once_t = 0; } // make sure this isn't a subclass if (self !== Swizzle.self) { return; } dispatch_once(&Static.token) { let originalSelector = Selector("method"); let swizzledSelector = Selector("methodExt"); let originalMethod = class_getInstanceMethod(self,originalSelector); let swizzledMethod = class_getInstanceMethod(self,swizzledSelector); print(method_getImplementation(originalMethod)); print(method_getImplementation(swizzledMethod)); let dIDAddMethod = class_addMethod(self,originalSelector,method_getImplementation(swizzledMethod),method_getTypeEnCoding(swizzledMethod)); if dIDAddMethod { class_replaceMethod(self,swizzledSelector,method_getImplementation(originalMethod),method_getTypeEnCoding(originalMethod)); } else { method_exchangeImplementations(originalMethod,swizzledMethod); } print(method_getImplementation(originalMethod)); print(method_getImplementation(swizzledMethod)); } } func methodExt() { print("B"); }} 然后我尝试用它来执行它
var s = Swizzle();s.method();
预期输出为“B”,但仍然打印“A”.从我的代码中可以看出,我在swizzle *** 作之前和之后都包含了每个IMP的打印件.这些打印显示交换确实发生,但输出保持不变.
输出:
0x000000010251a9200x000000010251ad400x000000010251ad400x000000010251a920A
在让这些更改生效时,我有什么遗漏吗?
PS.目前正在使用XCode 7.0.1
解决方法 问题是你的method()缺少动态指令:class Swizzle: NSObject{ dynamic func method() { print("A") }} 修改声明,它应该工作.
在Swift中使用方法调配时,您的类/方法必须符合以下两个要求:
>您的课程必须扩展NSObject
>您想要调配的函数必须具有动态属性
有关为何需要此 *** 作的完整说明,请查看Using Swift with Cocoa and Objective-C:
Requiring Dynamic dispatchWhile the
@objcattribute exposes your Swift API to the Objective-C
runtime,it does not guarantee dynamic dispatch of a property,method,
subscript,or initializer. The Swift compiler may still devirtualize
or inline member access to optimize the performance of your code,
bypassing the Objective-C runtime. When you mark a member declaration
with thedynamicmodifIEr,access to that member is always dynamically
dispatched. Because declarations marked with thedynamicmodifIEr are
dispatched using the Objective-C runtime,they’re implicitly marked
with the@objcattribute.Requiring dynamic dispatch is rarely necessary. However,you must use
thedynamicmodifIEr when you kNow that the implementation of an API
is replaced at runtime. For example,you can use the
method_exchangeImplementationsfunction in the Objective-C runtime to
swap out the implementation of a method while an app is running. If
the Swift compiler inlined the implementation of the method or
devirtualized access to it,the new implementation would not be used.
Swift 3更新:
关于GCD已经有一些变化,并且dispatch_once不再可用.为了执行相同的一次 *** 作,我们可以将代码包含在全局静态类常量的初始化块中.
Swift语言保证此代码在应用程序的生命周期内仅执行一次.
class TestSwizzling : NSObject { dynamic func methodone()->Int{ return 1 }}extension TestSwizzling { //In Objective-C you'd perform the swizzling in load(),//but this method is not permitted in Swift overrIDe class func initialize() { struct Inner { static let i: () = { let originalSelector = #selector(TestSwizzling.methodone) let swizzledSelector = #selector(TestSwizzling.methodTwo) let originalMethod = class_getInstanceMethod(TestSwizzling.self,originalSelector); let swizzledMethod = class_getInstanceMethod(TestSwizzling.self,swizzledSelector) method_exchangeImplementations(originalMethod,swizzledMethod) } } let _ = Inner.i } func methodTwo()->Int{ // It will not be a recursive call anymore after the swizzling return methodTwo()+1 }}var c = TestSwizzling()print(c.methodone())print(c.methodTwo()) Swift 2.2更新:
我已经为新的#selector属性更新了原始示例:
class TestSwizzling : NSObject { dynamic func methodone()->Int{ return 1 }}extension TestSwizzling { //In Objective-C you'd perform the swizzling in load(),//but this method is not permitted in Swift overrIDe class func initialize() { struct Static { static var token: dispatch_once_t = 0 } // Perform this one time only dispatch_once(&Static.token) { let originalSelector = #selector(TestSwizzling.methodone) let swizzledSelector = #selector(TestSwizzling.methodTwo) let originalMethod = class_getInstanceMethod(self,originalSelector); let swizzledMethod = class_getInstanceMethod(self,swizzledMethod) } } func methodTwo()->Int{ // It will not be a recursive call anymore after the swizzling return methodTwo()+1 }}var c = TestSwizzling()print(c.methodone())print(c.methodTwo()) 如果您需要一个示例,请查看此示例项目on github.
总结以上是内存溢出为你收集整理的ios – 方法Swizzling不起作用全部内容,希望文章能够帮你解决ios – 方法Swizzling不起作用所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)