2015-07-08 18 views
14

Ostatecznie rzecz biorącJak poprawnie przekazać selektor jako parametr w szybkim

mam klasy A, który zawiera wystąpień B. aw klasie A, mijam funkcję jako selektor sposobu B. i B użyj tego selektora, aby zarejestrować powiadomienie. Jednak po otrzymaniu powiadomienia nie można uruchomić selektora i pokazać "nierozpoznany selektor wysłany do instancji". Jeśli przeniesie wszystko, co chcę zrobić w klasie B do klasy A, zadziałało. Jednak chcę je rozdzielić, żeby wyglądały na bardziej zorganizowane. Jestem całkiem nowy w Objective-C i Swift, dlatego nie wiem jak przekazać selektor jako parametr w tym przypadku. Odpowiedź w Swift byłaby świetna.

ViewController.swift

class ViewController: UIViewController { 

    var sessionCtrl : GKSessionControllerH! 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     // Do any additional setup after loading the view, typically from a nib. 

     sessionCtrl = GKSessionControllerH() 

     // register notifications 
     registerNotification() 
    } 

    func registerNotification() { 
     sessionCtrl.registerNotification(GKGesture.Up, gestureHandler: "gestureUpHandler") 
    } 

    func gestureUpHandler() { 
     dispatch_async(dispatch_get_main_queue()) { 
      self.slidesViewCtrl!.prevPage() 
     } 
    } 
} 

GKSessionControllerH.swift

class GKSessionControllerH: NSObject, WCSessionDelegate { 

    func handleGestureContent(content : AnyObject?) { 

     // retrieve gesture 
     let gesture = GKGesture(rawValue: content as! String)! 
     print("Handheld device receives \(gesture)") 

     // post notification 
     let notificationName = "ReceiveGesture\(gesture.rawValue)" 
     NSNotificationCenter.defaultCenter().postNotificationName(notificationName, object: nil) 

    } 

    func registerNotification(gesture : GKGesture, gestureHandler : Selector) { 

     let notificationName = "ReceiveGesture\(gesture.rawValue)" 
     NSNotificationCenter.defaultCenter().addObserver(self, selector: gestureHandler, name: notificationName, object: nil) 

    } 
} 

informacji debugowania

2015-07-08 17:26:26.534 Slider[4608:1719498] -[Slider.GKSessionControllerH gestureDownHandler]: unrecognized selector sent to instance 0x7f912857a420 
2015-07-08 17:26:26.543 Slider[4608:1719498] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Slider.GKSessionControllerH gestureDownHandler]: unrecognized selector sent to instance 0x7f912857a420' 
*** First throw call stack: 
(
    0 CoreFoundation      0x000000010430dca5 __exceptionPreprocess + 165 
    1 libobjc.A.dylib      0x00000001060f1dcd objc_exception_throw + 48 
    2 CoreFoundation      0x0000000104315fcd -[NSObject(NSObject) doesNotRecognizeSelector:] + 205 
    3 CoreFoundation      0x00000001042634ea ___forwarding___ + 970 
    4 CoreFoundation      0x0000000104263098 _CF_forwarding_prep_0 + 120 
    5 CoreFoundation      0x00000001042db09c __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 12 
    6 CoreFoundation      0x00000001042daddb _CFXRegistrationPost + 427 
    7 CoreFoundation      0x00000001042dab42 ___CFXNotificationPost_block_invoke + 50 
    8 CoreFoundation      0x000000010431d432 -[_CFXNotificationRegistrar find:object:observer:enumerator:] + 1618 
    9 CoreFoundation      0x00000001041d3538 _CFXNotificationPost + 632 
    10 Foundation       0x00000001048bb3c4 -[NSNotificationCenter postNotificationName:object:userInfo:] + 66 
    11 Slider        0x00000001040f4e0e _TFC6Slider20GKSessionControllerH20handleGestureContentfS0_FGSqPSs9AnyObject__T_ + 1086 
    12 Slider        0x00000001040f4689 _TFC6Slider20GKSessionControllerH7sessionfS0_FTCSo9WCSession17didReceiveMessageGVSs10DictionarySSPSs9AnyObject___T_ + 825 
    13 Slider        0x00000001040f49b7 _TToFC6Slider20GKSessionControllerH7sessionfS0_FTCSo9WCSession17didReceiveMessageGVSs10DictionarySSPSs9AnyObject___T_ + 119 
    14 WatchConnectivity     0x00000001060c18cd WatchConnectivity + 35021 
    15 libdispatch.dylib     0x0000000106ab2b11 _dispatch_call_block_and_release + 12 
    16 libdispatch.dylib     0x0000000106ad280d _dispatch_client_callout + 8 
    17 libdispatch.dylib     0x0000000106ab92ec _dispatch_queue_drain + 2200 
    18 libdispatch.dylib     0x0000000106ab88ed _dispatch_queue_invoke + 233 
    19 libdispatch.dylib     0x0000000106abae9b _dispatch_root_queue_drain + 1412 
    20 libdispatch.dylib     0x0000000106aba912 _dispatch_worker_thread3 + 111 
    21 libsystem_pthread.dylib    0x0000000106e11637 _pthread_wqthread + 729 
    22 libsystem_pthread.dylib    0x0000000106e0f40d start_wqthread + 13 
) 
libc++abi.dylib: terminating with uncaught exception of type NSException 

Odpowiedz

12

Her e jest duża wskazówka w wyjścia konsoli:

- [Slider.GKSessionControllerH gestureDownHandler]: nierozpoznany selektor wysyłane do instancji 0x7f912857a420

Tak, problem jest to, że zamiast próbując wywołać gestureDownHandler na własną ViewController , GKSessionControllerH rejestruje się jako odbiorca powiadomienia.

Musimy przekazać oba selektory i do obiektu, aby wywołać selektor na.

func registerNotification(gesture: GKGesture, gestureHandler: AnyObject, selector: Selector) { 
    let notificationName = "ReceiveGesture\(gesture.rawValue)" 
    NSNotificationCenter.defaultCenter().addObserver(gestureHandler, selector: gestureHandler, name: notificationName, object: nil) 
} 

A teraz, aby zarejestrować:

sessionCtrl.registerNotification(.Up, gestureHandler: self, selector: "gestureUpHandler") 

Alternatywnie, i zapewne bardziej Swift-jak możemy brać więcej podejście oparte na zamknięcie.

Po pierwsze, zróbmy GKSessionControllerH otrzymywać powiadomienia, a my przekażemy to zamknięcie, które będzie śledzić, aby zadzwonić po otrzymaniu powiadomienia.

W GKSessionControllerH,

var gestureActions = [()->Void] // an array of void-void closures 

func gestureHandler() { 
    for action in gestureActions { 
     action() 
    } 
} 

func registerNotification(gesture: GKGesture, action:()->Void) { 
    let notificationName = "ReceiveGesture\(gesture.rawValue)" 
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "gestureHandler", name: notificationName, object: nil) 
} 

A teraz przechodzimy w zamknięciu (który może być metoda):

W ViewController:

func registerNotification() { 
    sessionCtrl.registerNotification(.Up, action: gestureUpHandler) 
} 

Teraz oczywiście będzie to potrzebne trochę więcej logiki, aby poradzić sobie z różnymi rodzajami gestów, ale ich istota jest tutaj.

Powiązane problemy