I was interested in using a UIGestureRecognizer subclass (UILongPressGestureRecognizer) in a ViewController Subclass I had. My ViewController has a UIToolBar and programmatically I can create a UILongPressGestureRecognizer instance attached to the UIToolBar and have everything work. My ViewController adopts the UIGestureRecognizerDelegate protocol. In the ViewController I have:
//My ViewController.h
@interface MyViewController: UIViewController<UIGestureRecognizerDelegate>
/* ... */
@property (nonatomic, retain) IBOutlet UIToolbar *toolbar;
@property (nonatomic, retain) IBOutlet UILongPressGestureRecognizer *longPressGesureRecognizer;
/* ... */
- (IBAction)handleGesture;
@end
The following code then works:
- (void)viewDidLoad
{
[super viewDidLoad];
//configure UILongPressGestureRecognizer
if(self.longPressGesureRecognizer == nil){
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture)];
longPress.minimumPressDuration = 1.5;
longPress.numberOfTouchesRequired = 1;
longPress.delegate = self;
self.longPressGesureRecognizer = longPress;
[self.toolbar addGestureRecognizer:self.longPressGesureRecognizer];
[longPress release];
}
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
return YES;
}
- (IBAction)handleGesture{
NSLog(@"Got a gesture!");
}
I didn't think I really need the UILongPressGestureRecognizer in my View Controller. When I tried to create it entirely in the MyViewController.xib file I did the following using XCode 4.2
When I go to run the Application in the Simulator I crash which the following gdb error in the console:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UILongPressGestureRecognizer initWithCoder:]: unrecognized selector sent to instance
Clearly UILongPressGestureRecognizer initWithCoder: isn't impelmented but I'm wondering what the correct way of setting up the UIGestureRecognizer is in the xib file. XCode has gestures there and I've connected it a view. I don't see what I'm going wrong. All links I've seen on UIGestureRecognizer including Apple's UIGestureRecognizer's class reference always uses the UIGestureRecognizer from code. I haven't seen an example using just the xib file to configure it.
I'm not too concerned with this issue because I can handle it with code in the ViewController but I'm confused why XCode allows the Gesture Recognizers to be added in the nib if UILongPressGestureRecognizer and/or UIGestureRecognizer don't conform to the NSCoding Protocol and initWithCoder will be called. My intuition says the problem is on my end on not Apple's but I'd love to understand what's going wrong.
Thanks!
Update
I seem to only see this behavior in testing when I use a UISplitViewController. If I create a ViewController based project the UIGestureRecognizer works as expected. If I add a a Gesture Recognizer onto the DetailView of a UISplitViewController app I get a crash like this:
2011-11-03 10:17:55.873 GestureSplitViewTest[1143:b603] -[UILongPressGestureRecognizer initWithCoder:]: unrecognized selector sent to instance 0x59696b0
2011-11-03 10:17:55.877 GestureSplitViewTest[1143:b603] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UILongPressGestureRecognizer initWithCoder:]: unrecognized selector sent to instance 0x59696b0'
*** Call stack at first throw:
(
0 CoreFoundation 0x011b15a9 __exceptionPreprocess + 185
1 libobjc.A.dylib 0x01305313 objc_exception_throw + 44
2 CoreFoundation 0x011b30bb -[NSObject(NSObject) doesNotRecognizeSelector:] + 187
3 CoreFoundation 0x01122966 ___forwarding___ + 966
4 CoreFoundation 0x01122522 _CF_forwarding_prep_0 + 50
5 UIKit 0x002fe9fd UINibDecoderDecodeObjectForValue + 2592
6 UIKit 0x002fe2f5 UINibDecoderDecodeObjectForValue + 792
7 UIKit 0x002ff6ac -[UINibDecoder decodeObjectForKey:] + 398
8 UIKit 0x00214979 -[UIRuntimeConnection initWithCoder:] + 212
9 UIKit 0x003d34a8 -[UIRuntimeOutletCollectionConnection initWithCoder:] + 64
10 UIKit 0x002fe9fd UINibDecoderDecodeObjectForValue + 2592
11 UIKit 0x002fe2f5 UINibDecoderDecodeObjectForValue + 792
12 UIKit 0x002ff6ac -[UINibDecoder decodeObjectForKey:] + 398
13 UIKit 0x00213c36 -[UINib instantiateWithOwner:options:] + 804
14 UIKit 0x00215ab7 -[NSBundle(UINSBundleAdditions) loadNibNamed:owner:options:] + 168
15 UIKit 0x000cb628 -[UIViewController _loadViewFromNibNamed:bundle:] + 70
16 UIKit 0x000c9134 -[UIViewController loadView] + 120
17 UIKit 0x000c900e -[UIViewController view] + 56
18 UIKit 0x000c7482 -[UIViewController contentScrollView] + 42
19 UIKit 0x000d7f25 -[UINavigationController _computeAndApplyScrollContentInsetDeltaForViewController:] + 48
20 UIKit 0x000d6555 -[UINavigationController _layoutViewController:] + 43
21 UIKit 0x000d7870 -[UINavigationController _startTransition:fromViewController:toViewController:] + 524
22 UIKit 0x000d232a -[UINavigationController _startDeferredTransitionIfNeeded] + 266
23 UIKit 0x001ed2e9 -[UILayoutContainerView layoutSubviews] + 226
24 QuartzCore 0x01888a5a -[CALayer layoutSublayers] + 181
25 QuartzCore 0x0188addc CALayerLayoutIfNeeded + 220
26 QuartzCore 0x018300b4 _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 310
27 QuartzCore 0x01831294 _ZN2CA11Transaction6commitEv + 292
28 UIKit 0x0001b9c9 -[UIApplication _reportAppLaunchFinished] + 39
29 UIKit 0x0001be83 -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 690
30 UIKit 0x00026617 -[UIApplication handleEvent:withNewEvent:] + 1533
31 UIKit 0x0001eabf -[UIApplication sendEvent:] + 71
32 UIKit 0x00023f2e _UIApplicationHandleEvent + 7576
33 GraphicsServices 0x00eb2992 PurpleEventCallback + 1550
34 CoreFoundation 0x01192944 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 52
35 CoreFoundation 0x010f2cf7 __CFRunLoopDoSource1 + 215
36 CoreFoundation 0x010eff83 __CFRunLoopRun + 979
37 CoreFoundation 0x010ef840 CFRunLoopRunSpecific + 208
38 CoreFoundation 0x010ef761 CFRunLoopRunInMode + 97
39 UIKit 0x0001b7d2 -[UIApplication _run] + 623
40 UIKit 0x00027c93 UIApplicationMain + 1160
41 GestureSplitViewTest 0x0000234a main + 170
42 GestureSplitViewTest 0x00002295 start + 53
)
terminate called throwing an exceptionsharedlibrary apply-load-rules all
Current language: auto; currently objective-c
(gdb)
Have you made sure that you are not using iOS 4.3 SDK instead of iOS 5 SDK?
I spent a good 30 minute to find out I was using the wrong SDK.