2016-07-01 3 views
0

개인 API MPAVRoutingController에서 사용 가능한 모든 airplay 장치를 가져 오려고합니다. performSelector-Swift라고하는 swift 용 타사 수행 셀렉터 라이브러리를 사용하고 있습니다. 호출하려는 메서드는 fetchAvailableRoutesWithCompletionHandler입니다. 하나의 매개 변수 인 objective-c 블록을 사용합니다. - (void)fetchAvailableRoutesWithCompletionHandler:(id /* block */)arg1; 폐쇄를 통과하려고하면 컴파일 오류가 발생하고 응용 프로그램에서 아무 것도 전달하지 않으면 충돌이 발생합니다. 이 응용 프로그램을 공개하지 않는 이유는 priv API를 사용하는 이유입니다. http://i.imgur.com/UGVayPE.png개인 API에 클로저 전달

그것으로 호출 완료 블록 파라미터로서 NSMutableArray를 할당 보여준다 I 올바른 완료 블록 서명 발견 방법

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

요구되는 클로저의 서명을 알고 계십니까? 즉, '객체'가 정확합니까? 전용 함수는 반드시 클로저를 사용하기 때문에 다른 매개 변수를 전달하려고하면 오류가 발생합니다. 또한 swift_performSelector는 객체 매개 변수에 대한 클로저를 허용합니까? 제 3 자의 lib의 의사가 그것에 대해 뭐라고 말합니까? – Gero

+0

미안 해요 나는 방법 서명을 붙여 넣은 줄 알았지 만 다른 뭔가를 붙여 넣어 권자. sig는 reverse engineerred 헤더 파일 (https://github.com/nst/iOS-Runtime-Headers/blob/master/Frameworks)에 따라'- (void) fetchAvailableRoutesWithCompletionHandler : (id/* block * /) arg1;' /MediaPlayer.framework/MPAVRoutingController.h). 라이브러리에 관해서는, 난 그냥 그것을 스크랩하고 Obj - C에서 응용 프로그램 의이 섹션을 작성하고 나중에 다리를 –

+0

Dang, 그 부분을 해명, 중요한 부분을 설명하지 않습니다.그러나 실제로'(^) (parameterTypes) '부분을 빠뜨린 것으로 가정하면, 블록이 최소한 id (즉, 신속한 AnyObject)를 반환해야하는 것처럼 보입니다. 그 머리글을 다음과 같이 이해할 것입니다 : "'id'를 반환하는 블록을 전달하십시오. 어쩌면'/ * ... */withObject : {() -> AnyObject in/*는 더미 객체를 정의하고/*})'를 시도해보십시오. 일반적으로 설정해야 할 매개 변수를 정확히 모른 채 리버스 엔지니어링 된 메서드를 호출하면 내 경험에 비추어 빠르게 신속하게 남쪽으로 내려갑니다. – Gero

답변

2

우선 ... 이것이 유일한 매개 변수입니다. 당신은 이것을 할 필요가 없습니다 (분해하십시오). 예외가 발생하면 서명을 인쇄 할 수 있습니다. 때로는 어떤 종류의 블록이 예상되는지 알려줄 것입니다. 전화가 여러 매개 변수를 포함하는 통증이 특히


다음, 동적 선택기를 호출에 대한 내 생각 ..

당신의 최선의 옵션은 선택기를 수행하지 않는 것입니다 .. 그것은 무엇 당신이 할 수있는

..입니다 do는 인터페이스/확장 포인터를 통한 호출이다. 나는 C++ (Pimpl 관용구의 아이디어 .. COMM 인터페이스도 이와 같이)에서 항상 이것을한다. Swift, Objective-C, Java 등에서도 사용한다.

동일한 인터페이스가있는 프로토콜을 만듭니다. e를 객체로 사용합니다. 해당 프로토콜을 상속하는 확장을 만듭니다. 그런 다음 객체 인스턴스를 해당 확장/인터페이스/프로토콜로 캐스팅합니다.

인터페이스/확장/프로토콜 포인터를 통해 원하는 기능을 호출하십시오.

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. 
} 

사용법 :

#import <Foundation/Foundation.h> 

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

@implementation NSObject (MPAVRoutingControllerProtocol) 

@end 
: 당신이 확장 + 프로토콜을 만드는 대신 브리징 헤더와 함께 할 것 인 경우에

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

MPAVRoutingController.fetchAvailableRoutesWithCompletionHandler! { (routes) in 
    print(routes); 
} 

, 당신은 하나의 목표 - C 범주를 다만 것 그런 다음

:

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

MPAVRoutingController.fetchAvailableRoutesWithCompletionHandler! { (routes) in 
    print(routes); 
} 

마지막으로 프로토콜 삽입을 사용할 수 있다면 다음과 같이 훨씬 쉽게 할 수 있습니다 :

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); 
} 
+1

그래, 그냥 생각하고 있었어. 감사! –

관련 문제