Conclusively speaking
I have class A that contains a instances of B. And in class A, I pass a function of A as selector to A method of B. And B use this selector to register notification. However, when the notification comes in, it could not run the selector and show "unrecognized selector sent to instance". If I move all what I want to do in class B into class A, it worked. However, I want them separated so that it seems more organized. I am fairly new to Objective-C and Swift, therefore, I don't know how to pass selector as parameter in this case. Answer in Swift would be great.
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) } }
debug info
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
Here's the big clue in your console output:
-[Slider.GKSessionControllerH gestureDownHandler]: unrecognized selector sent to instance 0x7f912857a420
So, the problem is that rather than attempting to call gestureDownHandler
on your ViewController
, GKSessionControllerH
is registering itself to be the receiver of the notification.
We need to pass in both the selector and the object to call the selector on.
func registerNotification(gesture: GKGesture, gestureHandler: AnyObject, selector: Selector) { let notificationName = "ReceiveGesture\(gesture.rawValue)" NSNotificationCenter.defaultCenter().addObserver(gestureHandler, selector: gestureHandler, name: notificationName, object: nil) }
And now, to register:
sessionCtrl.registerNotification(.Up, gestureHandler: self, selector: "gestureUpHandler")
Alternatively, and arguably more Swift-like, we can take a more closure-based approach.
First, let's make GKSessionControllerH
receive the notifications, and we'll pass it a closure, which it'll keep track of to call when the notification is received.
In 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) }
And now, we pass in a closure (which can be a method):
In ViewController
:
func registerNotification() { sessionCtrl.registerNotification(.Up, action: gestureUpHandler) }
Now obviously, this will need a little more logic to handle all your different gesture types, but the gist of it is here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With