本文介绍了方法Swizzling不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想利用方法调配,但我无法得到简单的例子来为我工作。我可能误解了这个概念是什么,但据我所知,它允许交换方法实现。



给定两种方法,A和B,我想交换他们的实现,这样调用A将执行B。我遇到了一些混合的例子(和)。我创建了一个带有类的新项目来测试它。

  class Swizzle:NSObject 
{
func method()
{
print(A);
}
}

扩展名Swizzle
{
覆盖类func initialize()
{
struct Static
{
static var token:dispatch_once_t = 0;
}

//确保这不是子类
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 的打印件。这些打印显示交易确实发生,但输出保持不变。



输出:

  0x000000010251a920 
0x000000010251ad40
0x000000010251ad40
0x000000010251a920
A

在让这些更改生效时,我有什么遗漏吗?



PS。目前正在使用XCode 7.0.1

解决方案

问题是您的方法()缺少动态指令:

  class Swizzle:NSObject 
{
dynamic func method()
{
print(A)
}
}

修改声明,它应该有效。



在Swift中使用方法调配时,有两个要求:你的类/方法必须符合:




  • 你的类必须扩展 NSObject

  • 您想要调配的函数必须具有动态属性



如需完整解释原因,请查看:

Swift 3 Update:

There have been a few changes in regard to GCD and dispatch_once is not available anymore. To perform the same one time operation, we can enclose the code in the initialization block of a global static class constant.

The Swift language guarantees that this code will be executed only once during the lifetime of the application.

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 Update:

I've updated the original example for the new #selector attribute:

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())

If you need an example to play with, check out this sample project on github.

这篇关于方法Swizzling不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-16 21:22
查看更多