无法识别的选择器调用“_setApplicationIsOpaque:”

时间:2017-05-01 13:42:04

标签: ios objective-c swift iphone-privateapi

我正在尝试访问iOS私有函数_setApplicationIsOpaque:(仅供个人使用和测试)。

我已经实现了这段代码:

@_silgen_name("_setApplicationIsOpaque:") func _setApplicationIsOpaque(_ arg1: Bool)

let invokeSetApplicationIsOpaque: (Bool) -> Void = {
    // The Objective-C selector for the method.
    let selector: Selector = Selector(("_setApplicationIsOpaque:"))
    guard case let method = class_getInstanceMethod(UIApplication.self, selector), method != nil else {
        fatalError("Failed to look up \(selector)")
    }

    // Recreation of the method's implementation function.
    typealias Prototype = @convention(c) (AnyClass, Selector, Bool) -> Void
    let opaqueIMP = method_getImplementation(method)
    let function = unsafeBitCast(opaqueIMP, to: Prototype.self)

    // Capture the implemenation data in a closure that can be invoked at any time.
    return{ arg1 in function(UIApplication.self, selector, arg1)}
}()

extension UIApplication {
    func setApplicationIsOpaque(_ isOpaque: Bool) {
        return invokeSetApplicationIsOpaque(isOpaque)
    }
}

我在以下StackOverflow问题here中找到了访问私有iOS API的方法 在GitHub的Access Private UIKit Function Without Using Bridging Header中。

问题是运行应用程序时出现错误

  

[UIApplication _setBackgroundStyle:]:无法识别的选择器发送到类0x10437f348

我找到了UIApplication this file的iOS私有API的标题。

1 个答案:

答案 0 :(得分:4)

- (void)_setApplicationIsOpaque:(BOOL)arg1;

实例方法(UIApplication),如下所示 最初的连字符-。实例方法被发送到实例 班级本身,而不是班级本身。

Objective-C方法是带有两个隐藏参数的C函数,比较 Messaging 在“Objective-C运行时编程指南”中:

  

它还传递了两个隐藏的参数:

     
      
  • 接收对象
  •   
  • 方法的选择器
  •   

对于实例方法,“接收对象”是实例 在您的情况下发送消息的UIApplication实例。 (对于类方法,它将是类对象)。

因此Swift扩展方法setApplicationIsOpaque 必须将self传递给闭包,并且必须将其传递给 实现方法的第一个参数:

let invokeSetApplicationIsOpaque: (UIApplication, Bool) -> Void = {
    // The Objective-C selector for the method.
    let selector = Selector(("_setApplicationIsOpaque:"))
    guard case let method = class_getInstanceMethod(UIApplication.self, selector), method != nil else {
        fatalError("Failed to look up \(selector)")
    }

    // Recreation of the method's implementation function.
    typealias Prototype = @convention(c) (UIApplication, Selector, Bool) -> Void
    let opaqueIMP = method_getImplementation(method)
    let function = unsafeBitCast(opaqueIMP, to: Prototype.self)

    // Capture the implemenation data in a closure that can be invoked at any time.
    return { (appl, arg1) in function(appl, selector, arg1)}
}()

extension UIApplication {
    func setApplicationIsOpaque(_ isOpaque: Bool) {
        return invokeSetApplicationIsOpaque(self, isOpaque)
    }
}

请注意,此处不需要_silgen_name声明。

@_silgen_name("_setApplicationIsOpaque:") func _setApplicationIsOpaque(_ arg1: Bool)

将Swift函数绑定到全局符号“_setApplicationIsOpaque”, 哪个不存在。如果要添加对该函数的调用

_setApplicationIsOpaque(true)

然后构建应用程序将因链接器错误而失败:

Undefined symbols for architecture x86_64:  "__setApplicationIsOpaque:"