Erste .. Wie ich den richtigen Abschluss Blocksignatur gefunden: http://i.imgur.com/UGVayPE.png
Das zeigt, dass es eine NSMutableArray
als Parameter zur Fertigstellung Block zuweist, wenn er sie aufruft. Das ist der einzige Parameter. Sie müssen das nicht tun (zerlegen Sie es). Wenn eine Ausnahme ausgelöst wird, können Sie die Signatur drucken. Manchmal wird es Ihnen auch sagen, welche Art von Block erwartet wird.
Als nächstes meine Meinung über Selektoren dynamisch aufrufen ..
Ihre beste Möglichkeit ist, um nicht Selektoren durchführen .. Es ist ein besonders Schmerz, wenn der Anruf mehrere Parameter enthält ..
Was können Sie do ist Aufruf durch Interface/Erweiterung Zeiger .. Ich mache dies in C++ (Idee von der Pimpl idiom .. COMM-Schnittstellen tun dies auch) die ganze Zeit und es funktioniert mit Swift, Objective-C, Java .. etc ..
Erstellen Sie ein Protokoll mit der gleichen Schnittstelle e als das Objekt. Erstellen Sie eine Erweiterung, die dieses Protokoll erbt. Übergeben Sie dann die Objektinstanz an diese Erweiterung/Schnittstelle/Protokoll.
Rufen Sie die gewünschte Funktion über die Schnittstelle/Erweiterung/Protokollzeiger auf.
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.
}
Verbrauch:
let MPAVRoutingControllerClass: NSObject.Type = NSClassFromString("MPAVRoutingController") as! NSObject.Type
let MPAVRoutingController: MPAProtocol = MPAVRoutingControllerClass.init() as MPAProtocol
MPAVRoutingController.fetchAvailableRoutesWithCompletionHandler! { (routes) in
print(routes);
}
Wenn Sie es mit einem Brückenkopf statt Erstellen der Erweiterung + Protokoll zu tun, würde man nur eine einzige Objective-C Kategorie tun:
#import <Foundation/Foundation.h>
@interface NSObject (MPAVRoutingControllerProtocol)
- (void)fetchAvailableRoutesWithCompletionHandler:(void(^)(NSArray *routes))completion;
@end
@implementation NSObject (MPAVRoutingControllerProtocol)
@end
Dann
:
let MPAVRoutingControllerClass: NSObject.Type = NSClassFromString("MPAVRoutingController") as! NSObject.Type
let MPAVRoutingController = MPAVRoutingControllerClass.init()
MPAVRoutingController.fetchAvailableRoutesWithCompletionHandler! { (routes) in
print(routes);
}
Schließlich, wenn Sie Protokoll-Injektion verwenden können, können Sie dies viel einfacher tun:
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);
}
Kennen Sie die Signatur der geforderten Schließung, d. H. Ist "Objekt" definitiv richtig? Weil die private Funktion sicher die Schließung für etwas verwendet und wenn es versucht, verschiedene Parameter zu übergeben, haben Sie einen Fehler. Akzeptiert Swift_performSelector sogar eine Schließung für den Objektparameter? Was sagt das Dokument dieser dritten Partei darüber? – Gero
Entschuldigung, ich dachte, ich habe die Methodensignatur eingefügt, aber ich habe etwas anderes eingefügt. Die Signatur ist '- (void) fetchAvailableRoutesWithCompletionHandler: (id/* block * /) arg1;' entsprechend der umgekehrten ingenieurmäßigen Headerdatei (https://github.com/nst/iOS-Runtime-Headers/blob/master/Frameworks /MediaPlayer.framework/MPAVRoutingController.h). Was die Bibliothek angeht, kann ich sie einfach verwerfen und diesen Teil der App in Obj-C schreiben und ihn später überbrücken –
Dang, das klärt es nicht, denn der wichtige Teil ist auskommentiert.Unter der Annahme, dass sie den '(^) (parameterTypes) '-Teil wirklich weggelassen haben, sieht es so aus, als ob der Block mindestens' id 'zurückgeben sollte (d. H.' AnyObject' in swift). Ich würde diesen Header so verstehen: "Übergeben Sie einen Block, der' id' zurückgibt. Also versuchen Sie vielleicht '/ * ... */withObject: {() -> AnyObject in/* definieren Sie ein Dummy-Objekt, geben Sie es zurück/*})'. Gewöhnlich ruft man Reverse Engineering-Methoden auf, ohne genau zu wissen, welche Parameter zu setzen sind, zumindest aus meiner Erfahrung. – Gero