本文介绍了如何使用 Swift 中的协议公开 Objective-C 对象的私有类方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑 UIColor 上的两个私有方法:

Consider two private methods on UIColor:

  1. 返回颜色的RGB字符串的实例方法styleString
  2. 返回破坏性按钮使用的红色的类方法 _systemDestructiveTintColor.

UIColor.h 私有头文件参考

例如方法,我可以创建一个 @objc 协议并使用 unsafeBitCast 来公开私有方法:

For instance methods, I can create an @objc protocol and use unsafeBitCast to expose the private method:

@objc protocol  UIColorPrivate {
    func styleString() -> UIColor
}

let white = UIColor.whiteColor()
let whitePrivate = unsafeBitCast(white, UIColorPrivate.self)
whitePrivate.styleString() // rgb(255,255,255)

但是,我不确定这对类方法有何作用.

However, I'm not sure how this would work for class methods.

第一次尝试:

@objc protocol UIColorPrivate {
    class func _systemDestructiveTintColor() -> String // Error: Class methods are only allowed within classes
}

有道理,我把它改成static:

@objc protocol UIColorPrivate {
    static func _systemDestructiveTintColor() -> String
}

let colorClass = UIColor.self
let privateClass = unsafeBitCast(colorClass, UIColorPrivate.self) // EXC_BAD_ACCESS

这会导致崩溃.嗯,这不会很快.我可以使用桥接头并将类方法公开为 @interface,但是有没有办法在纯 Swift 中公开这些私有类方法?

This causes a crash. Well this is going nowhere fast. I could use a bridging header and just expose the class methods as an @interface, but is there a way to expose these private class methods in pure Swift?

我可以用 performSelector 做到这一点,但我更愿意将该方法公开为接口或协议:

I could do this with performSelector, but I'd rather expose the method as an interface or protocol:

if UIColor.respondsToSelector("_systemDestructiveTintColor") {
    if let red = UIColor.performSelector("_systemDestructiveTintColor").takeUnretainedValue() as? UIColor {
        // use the color
    }
}

推荐答案

通过协议实现您想要的一种方法是为静态方法使用单独的协议.Objective-C 中的静态方法实际上是类元类上的实例方法,因此您可以安全地采用如下方法:

One way to achieve what you want via protocols is to use a separate protocol for the static method. Static methods in Objective-C are actually instance methods on the metaclass of the class, so you can safely take an approach like below:

@objc protocol UIColorPrivateStatic {
    func _systemDestructiveTintColor() -> UIColor
}

let privateClass = UIColor.self as! UIColorPrivateStatic
privateClass._systemDestructiveTintColor() // UIDeviceRGBColorSpace 1 0.231373 0.188235 1

这会让你同时暴露私有方法和协议的使用,并且你摆脱了丑陋的unsafeBitCast(并不是强制转换会更漂亮).

This will give you both exposure of the private method and usage of protocols, and you get rid of the ugly unsafeBitCast (not that a forced cast would be more beautiful).

请注意,与往常一样,如果您使用私有 API,如果 Apple 决定更改类的某些内部结构,您的代码随时可能会中断.

Just note that as always if you are working with private API's your code can break at any time if Apple decides to change some of the internals of the class.

这篇关于如何使用 Swift 中的协议公开 Objective-C 对象的私有类方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-14 05:48