Kev*_*vin 6 xcode ios swift method-swizzling swift2
我想利用方法调配,但我甚至无法得到简单的例子来为我工作.我可能误解了这个概念是什么,但据我所知,它允许交换方法实现.
给定两个方法A和B,我想交换它们的实现,这样调用A就会执行B.我遇到了一些混合的例子(example1和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");
}
}
Run Code Online (Sandbox Code Playgroud)
然后我尝试用它来执行它
var s = Swizzle();
s.method();
Run Code Online (Sandbox Code Playgroud)
预期输出为"B",但仍然打印"A".从我的代码中可以看出,我IMP在swizzle操作之前和之后都包含了每个打印件.这些打印显示交换确实发生,但输出保持不变.
输出:
0x000000010251a920
0x000000010251ad40
0x000000010251ad40
0x000000010251a920
A
Run Code Online (Sandbox Code Playgroud)
在让这些更改生效时,我有什么遗漏吗?
PS.目前正在使用XCode 7.0.1
Umb*_*ndi 13
问题是你method()缺乏dynamic指令:
class Swizzle: NSObject
{
dynamic func method()
{
print("A")
}
}
Run Code Online (Sandbox Code Playgroud)
修改声明,它应该工作.
在Swift中使用方法调配时,您的类/方法必须符合以下两个要求:
NSObjectdynamic属性有关为什么需要这样做的完整说明,请查看使用Swift与Cocoa和Objective-C:
需要动态调度
虽然该
@objc属性将Swift API暴露给Objective-C运行时,但它不保证动态调度属性,方法,下标或初始化程序.Swift编译器仍然可以通过半虚拟化或内联成员访问来优化代码的性能,从而绕过Objective-C运行时.使用dynamic修饰符标记成员声明时,始终会动态调度对该成员的访问.因为dynamic使用Objective-C运行时调度使用修饰符标记的声明,所以使用该@objc属性隐式标记它们.要求动态调度很少是必要的.但是,
dynamic当您知道在运行时替换API的实现时,必须使用修饰符.例如,您可以使用method_exchangeImplementationsObjective-C运行时中的 函数在应用程序运行时交换方法的实现.如果Swift编译器内联该方法的实现或对其进行虚拟化访问,则不会使用新的实现.
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())
Run Code Online (Sandbox Code Playgroud)
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, swizzledSelector)
method_exchangeImplementations(originalMethod, 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())
Run Code Online (Sandbox Code Playgroud)
如果您需要一个示例,请在github上查看此示例项目.
| 归档时间: |
|
| 查看次数: |
2584 次 |
| 最近记录: |