Ios 将闭包传递给私有API';s

Ios 将闭包传递给私有API';s,ios,swift,selector,iphone-privateapi,Ios,Swift,Selector,Iphone Privateapi,我正在尝试从私有API MPAVRoutingController获取所有可用的airplay设备。我正在为swift使用一个名为performSelector swift的第三方执行选择器库。我尝试调用的方法是fetchAvailableRoutesWithCompletionHandler。这需要一个参数,即objective-c块-(void)fetchAvailableOutesWithCompletionHandler:(id/*block*/)arg1当我尝试传递一个闭包时,我会得到

我正在尝试从私有API MPAVRoutingController获取所有可用的airplay设备。我正在为swift使用一个名为performSelector swift的第三方执行选择器库。我尝试调用的方法是fetchAvailableRoutesWithCompletionHandler。这需要一个参数,即objective-c块<代码>-(void)fetchAvailableOutesWithCompletionHandler:(id/*block*/)arg1当我尝试传递一个闭包时,我会得到一个编译错误,如果我没有传递任何东西,我的应用程序就会崩溃。我没有发布这个应用程序,这就是为什么我要使用privapi

let MPAVRoutingController = NSClassFromString("MPAVRoutingController")! as! NSObject.Type
let routingController = MPAVRoutingController.init()
if let availableRoutes = routingController.swift_performSelector("fetchAvailableRoutesWithCompletionHandler:", withObject: {
        object in
    }) {
        print(availableRoutes)
    }

首先。。我如何找到正确的完成区块签名:

这表明它在调用完成块时将
NSMutableArray
作为参数分配给它。这是唯一的参数。你不必这样做(拆开它)。抛出异常时,可以打印签名。有时,它还会告诉您需要哪种类型的块


接下来,我对动态调用选择器的看法

最好的选择是不执行选择器。。这是一种痛苦,尤其是当调用包含多个参数时

您可以通过接口/扩展指针进行调用。。我在C++中使用这个方法(PIPL语言中的想法…COMM接口也这样做),它与Swift,ObjuleC,java一起工作。等等

创建与对象具有相同接口的协议。创建继承该协议的扩展。然后将对象实例强制转换为该扩展/接口/协议

通过接口/扩展/协议指针调用所需的任何函数

import UIKit
import MediaPlayer

@objc
protocol MPAProtocol { //Functions must be optional. That way you don't implement their body when you create the extension.
    optional func availableRoutes() -> NSArray
    optional func discoveryMode() -> Int
    optional func fetchAvailableRoutesWithCompletionHandler(completion: (routes: NSArray) -> Void)
    optional func name() -> NSString
}

extension NSObject : MPAProtocol { //Needed otherwise casting will fail!

     //Do NOT implement the body of the functions from the protocol.
}
用法:

let MPAVRoutingControllerClass: NSObject.Type = NSClassFromString("MPAVRoutingController") as! NSObject.Type
let MPAVRoutingController: MPAProtocol = MPAVRoutingControllerClass.init() as MPAProtocol

MPAVRoutingController.fetchAvailableRoutesWithCompletionHandler! { (routes) in
    print(routes);
}
如果要使用桥接头而不是创建extension+协议,只需执行一个Objective-C类别:

#import <Foundation/Foundation.h>

@interface NSObject (MPAVRoutingControllerProtocol)
- (void)fetchAvailableRoutesWithCompletionHandler:(void(^)(NSArray *routes))completion;
@end

@implementation NSObject (MPAVRoutingControllerProtocol)

@end
最后,如果您可以使用协议注入,则可以更轻松地执行此操作:

func classFromString(cls: String, interface: Protocol?) -> NSObject.Type? {
    guard let interface = interface else {
        return NSClassFromString(cls) as? NSObject.Type
    }

    if let cls = NSClassFromString(cls) {
        if class_conformsToProtocol(cls, interface) {
            return cls as? NSObject.Type
        }

        if class_addProtocol(cls, interface) {
            return cls as? NSObject.Type
        }
    }
    return nil
}

func instanceFromString<T>(cls: String, interface: Protocol?) -> T? {
    return classFromString(cls, interface: interface)?.init() as? T
}



@objc
protocol MPAProtocol {
    optional func availableRoutes() -> NSArray
    optional func discoveryMode() -> Int
    optional func fetchAvailableRoutesWithCompletionHandler(completion: (routes: NSArray) -> Void)
    optional func name() -> NSString
}


let MPAVRoutingController: MPAProtocol = instanceFromString("MPAVRoutingController", interface: MPAProtocol.self)!

MPAVRoutingController.fetchAvailableRoutesWithCompletionHandler! { (routes) in
    print(routes);
}
func classFromString(cls:String,interface:Protocol?)->NSObject.Type?{
guard let接口=接口else{
将NSClassFromString(cls)返回为?NSObject.Type
}
如果让cls=NSClassFromString(cls){
如果类符合协议(cls,接口){
将cls作为NSObject返回。类型
}
如果类添加协议(cls,接口){
将cls作为NSObject返回。类型
}
}
归零
}
func instanceFromString(cls:String,interface:Protocol?)->T?{
返回classFromString(cls,接口:interface)?.init()作为?T
}
@objc
协议MPA协议{
可选func availableRoutes()->NSArray
可选func discoveryMode()->Int
可选func fetchAvailableRoutesWithCompletionHandler(完成:(路由:NSArray)->Void)
可选func name()->NSString
}
让MPAVRoutingController:MPAProtocol=instanceFromString(“MPAVRoutingController”,接口:MPAProtocol.self)!
MPAVRoutingController.fetchAvailableRoutesWithCompletionHandler!(路线)
印刷(路线);
}

首先。。我如何找到正确的完成区块签名:

这表明它在调用完成块时将
NSMutableArray
作为参数分配给它。这是唯一的参数。你不必这样做(拆开它)。抛出异常时,可以打印签名。有时,它还会告诉您需要哪种类型的块


接下来,我对动态调用选择器的看法

最好的选择是不执行选择器。。这是一种痛苦,尤其是当调用包含多个参数时

您可以通过接口/扩展指针进行调用。。我在C++中使用这个方法(PIPL语言中的想法…COMM接口也这样做),它与Swift,ObjuleC,java一起工作。等等

创建与对象具有相同接口的协议。创建继承该协议的扩展。然后将对象实例强制转换为该扩展/接口/协议

通过接口/扩展/协议指针调用所需的任何函数

import UIKit
import MediaPlayer

@objc
protocol MPAProtocol { //Functions must be optional. That way you don't implement their body when you create the extension.
    optional func availableRoutes() -> NSArray
    optional func discoveryMode() -> Int
    optional func fetchAvailableRoutesWithCompletionHandler(completion: (routes: NSArray) -> Void)
    optional func name() -> NSString
}

extension NSObject : MPAProtocol { //Needed otherwise casting will fail!

     //Do NOT implement the body of the functions from the protocol.
}
用法:

let MPAVRoutingControllerClass: NSObject.Type = NSClassFromString("MPAVRoutingController") as! NSObject.Type
let MPAVRoutingController: MPAProtocol = MPAVRoutingControllerClass.init() as MPAProtocol

MPAVRoutingController.fetchAvailableRoutesWithCompletionHandler! { (routes) in
    print(routes);
}
如果要使用桥接头而不是创建extension+协议,只需执行一个Objective-C类别:

#import <Foundation/Foundation.h>

@interface NSObject (MPAVRoutingControllerProtocol)
- (void)fetchAvailableRoutesWithCompletionHandler:(void(^)(NSArray *routes))completion;
@end

@implementation NSObject (MPAVRoutingControllerProtocol)

@end
最后,如果您可以使用协议注入,则可以更轻松地执行此操作:

func classFromString(cls: String, interface: Protocol?) -> NSObject.Type? {
    guard let interface = interface else {
        return NSClassFromString(cls) as? NSObject.Type
    }

    if let cls = NSClassFromString(cls) {
        if class_conformsToProtocol(cls, interface) {
            return cls as? NSObject.Type
        }

        if class_addProtocol(cls, interface) {
            return cls as? NSObject.Type
        }
    }
    return nil
}

func instanceFromString<T>(cls: String, interface: Protocol?) -> T? {
    return classFromString(cls, interface: interface)?.init() as? T
}



@objc
protocol MPAProtocol {
    optional func availableRoutes() -> NSArray
    optional func discoveryMode() -> Int
    optional func fetchAvailableRoutesWithCompletionHandler(completion: (routes: NSArray) -> Void)
    optional func name() -> NSString
}


let MPAVRoutingController: MPAProtocol = instanceFromString("MPAVRoutingController", interface: MPAProtocol.self)!

MPAVRoutingController.fetchAvailableRoutesWithCompletionHandler! { (routes) in
    print(routes);
}
func classFromString(cls:String,interface:Protocol?)->NSObject.Type?{
guard let接口=接口else{
将NSClassFromString(cls)返回为?NSObject.Type
}
如果让cls=NSClassFromString(cls){
如果类符合协议(cls,接口){
将cls作为NSObject返回。类型
}
如果类添加协议(cls,接口){
将cls作为NSObject返回。类型
}
}
归零
}
func instanceFromString(cls:String,interface:Protocol?)->T?{
返回classFromString(cls,接口:interface)?.init()作为?T
}
@objc
协议MPA协议{
可选func availableRoutes()->NSArray
可选func discoveryMode()->Int
可选func fetchAvailableRoutesWithCompletionHandler(完成:(路由:NSArray)->Void)
可选func name()->NSString
}
让MPAVRoutingController:MPAProtocol=instanceFromString(“MPAVRoutingController”,接口:MPAProtocol.self)!
MPAVRoutingController.fetchAvailableRoutesWithCompletionHandler!(路线)
印刷(路线);
}

您是否知道所需关闭的签名,即
对象是否绝对正确?因为私有函数肯定会对某些东西使用闭包,如果它试图传递不同的参数,则会出现错误。此外,swift_performSelector是否接受对象参数的闭包?第三方库的文档对此有何评论?抱歉,我以为我粘贴了方法签名,但我粘贴了其他内容。该签名是
-(void)fetchAvailableRoutesWithCompletionHandler:(id/*block*/)arg1根据反向工程头文件()。至于图书馆,我可以把它扔掉