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

#ios #uisplitviewcontroller #xib #uigesturerecognizer #nib

#iOS #uisplitviewcontroller #xib #uigesturerecognizer #nib

Вопрос:

Мне было интересно использовать подкласс 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 (прикрепленный к панели инструментов в MyViewController).
  • Установите свойство делегата UILongPressRecognizer для владельца файла
  • Установите свойство selector в сообщение handleGesture MyViewController.

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

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

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

Меня не слишком беспокоит эта проблема, потому что я могу справиться с ней с помощью кода в ViewController, но я не понимаю, почему XCode позволяет добавлять распознаватели жестов в nib, если 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)
  

Комментарии:

1. Спасибо за этот вопрос, у меня была такая же проблема. Кто-нибудь сообщал о проблеме с радаром?

Ответ №1:

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

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

Комментарии:

1. Я провел быстрый тест и подтвердил, что вы были правы. Приложение загружается с помощью UISplitViewController с использованием SDK 5.0, но не SDK 4.3, и работает нормально, независимо от того, используется ли обычный подкласс UIViewController.

Ответ №2:

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

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

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

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

Комментарии:

1. Я попробовал это снова с пустым проектом, и это сработало, как вы сказали. Я добавил UILongPressGestureRecognizer, перетащив UIToolbar только в nib, и подключил к нему функцию IBAction в моем ViewController, и она работала, как ожидалось. Я немного углублюсь в свой другой проект, чтобы попытаться понять, в чем дело, но я думаю, что это работает так, как ожидалось. Надеюсь, в ближайшее время.

2. Модифицировал вопрос с учетом новых знаний о том, что это происходит в приложении на основе UISplitViewController.

Ответ №3:

Не рекомендуется менять версию SDK, как кто-то ответил, из-за более позднего распространения. Он не сможет быть установлен на устройствах без 5.0 SDK.

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

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

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

А также напишите это для обработки действия жеста

 - (void)swipe:(id)sender { ... }