Question

I am working on making an existing iPhone/iPad project backwards compatible down to iPhoneOS 3.0.

My current test device is an iPod Touch with 3.1.3 on it.

The following bit of code is causing problems:

Class gestureRecognizer = NSClassFromString(@"UISwipeGestureRecognizer");

if (gestureRecognizer != nil)
{

    UISwipeGestureRecognizer * leftSwipeRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self 
                                                                                               action:@selector(didSwipeLeft:)];
    leftSwipeRecognizer.direction = UISwipeGestureRecognizerDirectionLeft;
    leftSwipeRecognizer.delegate = self;
    [self.view addGestureRecognizer:leftSwipeRecognizer];
    _leftSwipeRecognizer = leftSwipeRecognizer;
}

According to Apple documentation UIGestureRecognizer is defined starting from iOS 3.2. So I expect Class gestureReconizer to be nil on previous OS version and that the following if to be skipped. However it does not skip. gestureRecognizer is not nil, the code inside the if starts executing and crashes at leftSwipeRecognizer.direction because:

-[UISwipeGestureRecognizer setDirection:]: unrecognized selector sent to instance 0x1e5720

This situation is quite confusing. I guess I am doing everything by the book. I try to check if a class exists before I use it, however the class which shouldn't be there, is there, fools my test, does not comply with its expected specs, and crashes.

I could, of course put a few respondsToSelector checks here and there to work around this crash, but it wouldn't be an elegant way to do it.

Any other suggestions?

Was it helpful?

Solution

According to the UIGestureRecognizer class reference, under "Usage Special Considerations", you actually do need to do an additional respondsToSelector check after checking if the class exists.

This is directly from the documentation:

To determine whether a class is available at runtime in a given iOS release, you typically check whether the class is nil. Unfortunately, this test is not cleanly accurate for UIGestureRecognizer. Although this class was publicly available starting with iOS 3.2, it was in development a short period prior to that. Although the class exists in an earlier release, use of it and other gesture-recognizer classes are not supported in that earlier release. You should not attempt to use instances of those classes.

To determine at runtime whether you can use gesture recognizers in your application, test whether the class exists and, if it does, allocate an instance and see check if it responds to the selector locationInView:. This method was not added to the class until iOS 3.2. The code might look like the following:

UIGestureRecognizer *gestureRecognizer = [[UIGestureRecognizer alloc] 
    initWithTarget:self action:@selector(myAction:)];

if (![gestureRecognizer respondsToSelector:@selector(locationInView:)]) {
    [gestureRecognizer release];
    gestureRecognizer = nil;
}
// do something else if gestureRecognizer is nil
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top