Почему создание подкласса UIGestureRecognizer в пере вызывает сбой при использовании UISplitViewController

Мне было интересно использовать подкласс UIGestureRecognizer (UILongPressGestureRecognizer) в подклассе ViewController, который у меня был. В моем ViewController есть UIToolBar, и программно я могу создать экземпляр UILongPressGestureRecognizer, прикрепленный к UIToolBar, и все будет работать. Мой ViewController использует протокол UIGestureRecognizerDelegate. В ViewController у меня есть:

//My ViewController.h
@interface MyViewController: UIViewController<UIGestureRecognizerDelegate>
/* ... */

@property (nonatomic, retain) IBOutlet UIToolbar *toolbar;
@property (nonatomic, retain) IBOutlet UILongPressGestureRecognizer *longPressGesureRecognizer;

/* ... */

- (IBAction)handleGesture;

@end

Затем работает следующий код:

- (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!");
}

Я не думал, что мне действительно нужен UILongPressGestureRecognizer в моем контроллере представления. Когда я попытался создать его полностью в файле MyViewController.xib, я сделал следующее, используя XCode 4.2.

  • Перетащил UILongPressRecognizer на свой UIToolBar в xib (прикреплен к toolBar в MyViewController).
  • Установите для свойства делегата UILongPressRecognizer значение владельца файла.
  • Установите свойство селектора на сообщение handleGesture MyViewController.

Когда я запускаю приложение в симуляторе, я выхожу из строя, что приводит к следующей ошибке gdb в консоли:

 *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UILongPressGestureRecognizer initWithCoder:]: unrecognized selector sent to instance

Очевидно, что UILongPressGestureRecognizer initWithCoder: не принудительно, но мне интересно, какой правильный способ настройки UIGestureRecognizer находится в файле xib. В XCode есть жесты, и я подключил к нему представление. Я не понимаю, что я делаю не так. Все ссылки, которые я видел в UIGestureRecognizer, включая от Apple, Ссылка на класс UIGestureRecognizer всегда использует UIGestureRecognizer из кода. Я не видел примера, использующего только файл xib для его настройки.

Меня не слишком беспокоит эта проблема, потому что я могу справиться с ней с помощью кода в ViewController, но меня смущает, почему XCode позволяет добавлять распознаватели жестов в перо, если UILongPressGestureRecognizer и / или UIGestureRecognizer не соответствуют протоколу NSCoding и будет вызван initWithCoder. Моя интуиция подсказывает, что проблема на моей стороне, а не на Apple, но я хотел бы понять, что происходит не так.

Спасибо!

Обновить

Я, кажется, вижу такое поведение только при тестировании, когда использую UISplitViewController. Если я создаю проект на основе ViewController, UIGestureRecognizer работает должным образом. Если я добавлю распознаватель жестов в DetailView приложения UISplitViewController, я получу вот такой сбой:

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)

person Joel    schedule 02.11.2011    source источник
comment
Спасибо за этот вопрос, у меня была такая же проблема. Кто-нибудь регистрировал проблему с радаром?   -  person Stephen Eilert    schedule 15.03.2012


Ответы (3)


Вы удостоверились, что не используете iOS 4.3 SDK вместо iOS 5 SDK?

Я потратил добрых 30 минут, чтобы узнать, что использую неправильный SDK.

person Your Friend    schedule 04.11.2011
comment
Я провел быструю проверку и подтвердил, что вы были правы. Приложение загружается с UISplitViewController с использованием SDK 5.0, но не SDK 4.3, и отлично работает независимо от того, используется ли обычный подкласс UIViewController. - person Joel; 04.11.2011

Требуется только разместить UILongPressRecognizer, а затем настроить IBAction, например

In H: -(IBAction)LongPress;
In M: -(IBAction)LongPress {
   NSLog(@"Good!");
}

Последним подключите его к UILongPressRecognizer. Сделанный! Проверено и работает.

Надеюсь это поможет!

person Your Friend    schedule 03.11.2011
comment
Я попробовал это снова с пустым проектом, и он сработал, как вы сказали. Я добавил UILongPressGestureRecognizer, перетащив UIToolBar только в перо, и подключил к нему функцию IBAction в моем ViewController, и все заработало, как ожидалось. Я немного углублюсь в свой другой проект, чтобы попытаться понять, что происходит, но я думаю, что он работает так, как ожидалось. Надеюсь, скоро. - person Joel; 03.11.2011
comment
Изменен вопрос с учетом того, что он возникает в приложении на основе UISplitViewController. - person Joel; 03.11.2011

Из-за более позднего распространения не рекомендуется менять версию SDK, как кто-то ответил. Его нельзя будет установить на устройства без 5.0 SDK.

Вместо этого не добавляйте его в xib, вместо этого пишите код. Вот пример кода жеста смахивания

Напишите эту часть кода где-нибудь при инициализации представления, например. В этом

UISwipeGestureRecognizer *_swipeGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipe:)];
[_swipeGestureRecognizer setDirection:UISwipeGestureRecognizerDirectionLeft];
[_swipeGestureRecognizer setNumberOfTouchesRequired:1];
[self addGestureRecognizer:_swipeGestureRecognizer];

А также напишите это, чтобы обрабатывать действие жеста

- (void)swipe:(id)sender { ... }
person zvjerka24    schedule 07.08.2012