首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何与测试包一起使用swizzle主包

如何与测试包一起使用swizzle主包
EN

Stack Overflow用户
提问于 2017-12-04 10:08:21
回答 1查看 1K关注 0票数 1

我使用swizzle主包和测试包,如obj c中的下面所示

代码语言:javascript
复制
#import "NSBundle+Bundle.h"
#import <objc/runtime.h>

@implementation NSBundle (Bundle)

+(void)loadSwizzler {
    static dispatch_once_t once_token;
    dispatch_once(&once_token,  ^{
        Method originalMethod = class_getClassMethod(self, @selector(mainBundle));
        Method extendedMethod = class_getClassMethod(self, @selector(bundleForTestTarget));
        //swizzling mainBundle method with our own custom method
        method_exchangeImplementations(originalMethod, extendedMethod);
    });
}

//method for returning app Test target
+(NSBundle *)bundleForTestTarget {
    NSBundle * bundle = [NSBundle bundleWithIdentifier:@"Philips.AppInfraTests"];

    return bundle;
}

@end

但我还是迅速地尝试了下面的方法

代码语言:javascript
复制
     extension Bundle {
  class func swizzle() {
        let originalSelector = #selector(mainBundle)
        let swizzledSelector = #selector(testBundle)
        let originalMethod = class_getInstanceMethod(self, originalSelector)
        let swizzledMethod = class_getInstanceMethod(self, swizzledSelector)
        method_exchangeImplementations(originalMethod, swizzledMethod)
    }

    func mainBundle() -> Bundle
    {
        return Bundle.main
    }
    func testBundle() -> Bundle
    {
        return Bundle(for: self.classNamed("swizzler")!)
    }
}

但这是抛出了一些错误“‘选择器’的参数不能引用变量'testBundle'”

有人能帮我怎么做吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-12-04 20:00:56

这个答案已经在Swift 3&4游乐场,任何其他版本和YMMV.中测试过。

您的目标-C代码使用两个类方法,Swift版本尝试使用两个实例方法,因此它们不是在做相同的事情。

您(可能)不能使用swizzle a(纯) Swift函数,您可以使用swizzle Objective方法,这是由于函数/方法的分派方式不同造成的。因此,在Swift中,替换函数必须在Swift 4中标记为@objc (在Swift 3中它是可选的,显然是无害的)。

Swift将mainBundle重命名为main,并将其作为属性进行表面处理,因此要获得mainBundle的选择器,需要使用getter: main

结合上面的内容,您将得到以下游乐场代码:

代码语言:javascript
复制
extension Bundle
{
    class func swizzle()
    {
        let originalSelector = #selector(getter: main)
        let swizzledSelector = #selector(testBundle)
        let originalMethod = class_getClassMethod(self, originalSelector)!
        let swizzledMethod = class_getClassMethod(self, swizzledSelector)!
        method_exchangeImplementations(originalMethod, swizzledMethod)
    }

    @objc class func testBundle() -> Bundle
    {
        // just for testing in Playground
        return Bundle(path: "/Applications/TextEdit.app")!
    }
}

let b = Bundle.main
print(b)
Bundle.swizzle()
let c = Bundle.main
print(c)

其中的指纹:

代码语言:javascript
复制
NSBundle </Applications/Xcode.app> (not yet loaded)
NSBundle </Applications/TextEdit.app> (not yet loaded)

注意,class_getClassMethod()返回一个Method?,上面的代码强制这样做,而不需要任何检查,这些检查应该在实际代码中存在

最后,请注意,您的swizzle代码假设mainBundle是由NSBundle直接实现的,而不是它的祖先之一,在这种情况下,这可能是一个安全的假设,但并不总是这样。例如,看看this question如何安全地执行抖动操作。

HTH

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47630884

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档