Deepak ML
Deepak ML

Reputation: 79

iphone- conditionally calling UIRefreshControl for IOS 6

I am trying to add UIRefreshControl for IOS 6.

#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v)     ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending)

if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"6.0")) {
    UIRefreshControl *refresh = [[UIRefreshControl alloc] init];
    refresh.attributedTitle = [[NSAttributedString alloc] initWithString:@"Pull to Refresh"];
    [refresh addTarget:self action:@selector(refreshView:)
      forControlEvents:UIControlEventValueChanged];
    self.refreshControl = refresh;
}

and

if (NSClassFromString(@"UIRefreshControl") != Nil) {
    UIRefreshControl *refresh = [[UIRefreshControl alloc] init];
    refresh.attributedTitle = [[NSAttributedString alloc] initWithString:@"Pull to Refresh"];
    [refresh addTarget:self action:@selector(refreshView:)
      forControlEvents:UIControlEventValueChanged];
    self.refreshControl = refresh;
}

but getting the error

dyld: Symbol not found: _OBJC_CLASS_$_UIRefreshControl
Referenced from: /Users/office/Library/Application Support/iPhone    Simulator/4.3.2/Applications/DD532E42-77F9-471C-AA48-7F9EAE9268C6/Verizon.app/Verizon
Expected in:   /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/i PhoneSimulator4.3.sdk/System/Library/Frameworks/UIKit.framework/UIKit

i am using IOS 6 SDK and running on iPhone 4.3 Simulator.

When i remove the code

    UIRefreshControl *refresh = [[UIRefreshControl alloc] init];
    refresh.attributedTitle = [[NSAttributedString alloc] initWithString:@"Pull to Refresh"];
    [refresh addTarget:self action:@selector(refreshView:)
      forControlEvents:UIControlEventValueChanged];
    self.refreshControl = refresh;

everything works for iPhone 4.3 Simulator. Interestingly code inside

if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"6.0")) {  }

never gets called when on iPhone 4.3 Simulator, not sure why the error. Please Help!!

Upvotes: 1

Views: 1807

Answers (2)

mattjgalloway
mattjgalloway

Reputation: 34912

Definitely go with the second style, i.e.:

if (NSClassFromString(@"UIRefreshControl") != nil) {
    ...
}

As for the error you are getting, you should be able to stop that by setting UIKit to "Optional" within the "Link binary with libraries" section of the project's "Build Phases" settings.

It should mark it as optional for you as it notices you're using a class that's only available in iOS 6, but looks like it's not in your case for some reason.

Upvotes: 1

user529758
user529758

Reputation:

Nevermind the code doesn't get called - when the application loads, the dynamic linker needs to resolve all the symbols in the dynamic libraries the app's binary is linked to. In iOS 4.3, the UIRefreshControl class is not implemented, so on devices running this OS (and any OS earlier than iOS 6) the operating system itself (well, rather its UIKit framework) doesn't contain the class and the symbol corresponding to it, so the application can't even start, even if it doesn't use the code suited for iOS6-only.

You also need to know that preprocessor macros are evaluated at compile time, and if your target is iOS 6, the code that you conditionally compile gets compiled and the system will try to execute that regardless of what version of iOS you're running the program on.

The solution: instead of using conditional compilation, use reflection and self-introspection to find out if the class is available at runtime:

Class UIRefreshControl_Class;
if ((UIRefreshControl_Class = objc_getClass("UIRefreshControl")) != Nil) {
    // class available
    id control = [[UIRefreshControl_class alloc] init];
    // etc.
}

Upvotes: 1

Related Questions