Swift 4 中的方法混淆

7

在Swift 4中,Swizzling不再起作用。

Method 'initialize()'定义了Objective-C类方法'initialize',这在Swift中是不允许的。

我已经找到了解决方案,因此想为其他人留下问题和答案。

1个回答

8

initialize()不再公开: 方法'initialize()'定义了Objective-C类方法'initialize',Swift不允许

现在的解决方法是通过公共静态方法运行您的交换代码。

例如

在扩展中: (此扩展用于kickstarter开源代码:https://github.com/kickstarter/ios-oss/blob/master/Library/DataSource/UIView-Extensions.swift

private var hasSwizzled = false

extension UIView {
    final public class func doBadSwizzleStuff() {
        guard !hasSwizzled else { return }

        hasSwizzled = true
        swizzle(self) /* This is pseudo - run your method here */
    }
}

在应用程序委托中: (这个方法在kickstarter开源代码中使用: https://github.com/kickstarter/ios-oss/blob/7c827770813e25cc7f79a28fa151cd713efe936f/Kickstarter-iOS/AppDelegate.swift#L33
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: UIApplicationLaunchOptionsKey: Any]?) -> Bool 
{
    UIView.doBadSwizzleStuff()
}

另一种方法是使用单例模式:

extension UIView {
    static let shared : UIViewController = {
        $0.initialize()
        return $0
    }(UIViewController())

    func initialize() {
        // make sure this isn't a subclass
        guard self === UIViewController.self else { return }

        let swizzleClosure: () = {
            UIViewController().swizzle() /* This is pseudo - run your method here */
        }()
        swizzleClosure
    }
}

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: UIApplicationLaunchOptionsKey: Any]?) -> Bool 
{
    _  = UIViewController.shared
}

3
只有当您可以访问AppDelegate源代码时,此方法才有效。我正在编写一个库,并希望在ViewController的“viewDidLoad”块中运行特定方法时使用方法交换(Swizzling)。我试图使我的库对客户尽可能容易实现,虽然我可以要求他们添加代码到AppDelegate中,但我宁愿使用方法交换(Swizzling)(并提供禁用选项)。有没有关于如何在Swift 4.0中实现"无需AppDelegate"的方法交换工作的想法?谢谢! Craig - CPR
1
{btsdaf} - Christopher Rex
1
{btsdaf} - CPR
1
刚刚又找到了那篇文章,没错就是那篇。我本来是来这里给你发链接的。 - Christopher Rex
@CPR 我刚刚偶然发现了这个答案和jordansmith.io的帖子。有人评论说在13.4之后这个方法不起作用,我已经验证过了。有没有人有解决方案,在没有访问AppDelegate的情况下在应用程序启动时调用swizzling? - Ryan C. Payne
@RyanC.Payne 我发现唯一的方法是使用 ObjC 类别开始 swizzle。其余的代码可以用 Swift 编写,但是无法避免使用一点 ObjC 来启动 swizzle。 - CPR

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接