ios - Cómo pasar correctamente el selector como parámetro en swift
(1)
Aquí está la gran pista en la salida de su consola:
- [Slider.GKSessionControllerH gestionDownHandler]: selector no reconocido enviado a la instancia 0x7f912857a420
Entonces, el problema es que en lugar de intentar llamar a gestureDownHandler
en su ViewController
, GKSessionControllerH
está registrando para ser el receptor de la notificación.
Necesitamos pasar tanto el selector como el objeto para activar el selector.
func registerNotification(gesture: GKGesture, gestureHandler: AnyObject, selector: Selector) {
let notificationName = "ReceiveGesture/(gesture.rawValue)"
NSNotificationCenter.defaultCenter().addObserver(gestureHandler, selector: gestureHandler, name: notificationName, object: nil)
}
Y ahora, para registrarte:
sessionCtrl.registerNotification(.Up, gestureHandler: self, selector: "gestureUpHandler")
Alternativamente, y posiblemente más Swift-like, podemos adoptar un enfoque más basado en el cierre.
Primero, hagamos que GKSessionControllerH
reciba las notificaciones, y le pasaremos un cierre, que mantendrá un registro de las llamadas cuando se reciba la notificación.
En 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)
}
Y ahora, pasamos en un cierre (que puede ser un método):
En ViewController
:
func registerNotification() {
sessionCtrl.registerNotification(.Up, action: gestureUpHandler)
}
Ahora, obviamente, esto necesitará un poco más de lógica para manejar todos sus diferentes tipos de gestos, pero la esencia de esto está aquí.
En conclusión, hablando
Tengo clase A que contiene instancias de B. Y en la clase A, paso una función de A como selector a un método de B. Y B usa este selector para registrar notificaciones. Sin embargo, cuando llega la notificación, no se pudo ejecutar el selector y mostrar "el selector no reconocido enviado a la instancia". Si muevo todo lo que quiero hacer en la clase B a la clase A, funcionó. Sin embargo, los quiero separados para que parezca más organizado. Soy bastante nuevo en Objective-C y Swift, por lo tanto, no sé cómo pasar el selector como parámetro en este caso. La respuesta en Swift sería genial.
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)
}
}
información de depuración
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