how i can exectute a function if the iOS version is above 4.* in a if statement?
Thanks
Please, take a look at weak linking of classes and methods in Apple's documentation — http://developer.apple.com/library/ios/#DOCUMENTATION/DeveloperTools/Conceptual/cross_development/Using/using.html they provide explicit instructions how to do support of multiple iOS'es in the same build. host answer from this big Apple's documentation:
if ([UIImagePickerController instancesRespondToSelector:
#selector (availableCaptureModesForCameraDevice:)]) {
// Method is available for use.
// Your code can check if video capture is available and,
// if it is, offer that option.
} else {
// Method is not available.
// Alternate code to use only still image capture.
}
Less flexible ways can be done on checking exact match of iOS by use of following code:
NSString *osVersion = [[UIDevice currentDevice] systemVersion];
You can do breakdown of osVersion to components and analyze them separately as numbers.
Cases when you class is not available for some particular iOS type is more complex and it is better to review a link to the document provided above.
Related
I am just started write app for ios.
I have 2 questions.
I know there are some codes which work fine in ios4.3 but don't work in ios5 and the opposite is also true.I want to know,which is the best practice for writing app both for ios4.3 and ios5?Is it acceptable run-time to check the version for specific parts of code??
I am also should write same app for ipad. So, I want to know which is the best practice for writing app for iphone which works also on ipad??
Thanks
iOS 5 or iOS 4
Another way to detect the version is to use the respondsToSelector: message on objects. The advantage compared to the version method is that you don't need to know what the next versions of iOS are gonna be to maintain your application. (What if, for instance, a new 5.0.2 version shows up? Your app should know that the "5.0.2" string is newer than "5.0"? I agree it would not be complicated to code, but using respondsToSelector: is much more convenient)
iPhone/iPod Touch or iPad
My usual way to code universal app (ie iPhone and iPad) is to define a basic implementation of my custom UIViewController classes, and then implement an HD version of it, inheriting the default behavior but customizing it for the iPad (overriding methods works well but the delegate pattern might be better: you get compilation warnings if you forget to implement methods).
If you use a different .xib file from the beginning of your application lifecycle (that's what you get by universal Xcode-provided templates), you may end up defining classes just from Interface Builder, and won't need to implement any runtime test in your code to know if you're running on an iPhone or an iPad.
You can get the version using:
[[UIDevice currentDevice] systemVersion];
The systemVersion returns a string, like "5.0". You can then compare the strings using string comparison. For example:
NSString *requiredVersion = #"5.0";
NSString *currentVersion = [[UIDevice currentDevice] systemVersion];
if ([currentVersion compare:requiredVersion options:NSNumericSearch] != NSOrderedAscending)
isItSupported = TRUE;
The documentation indicates that you can use the following to determine if you have an iPhone or iPad:
[[UIDevice currentDevice] model];
I've not used this though.
See the documentation.
i'm trying to add printing features to an ios app.
while printing itself works fine, and the app works on ios > 4, i haven't figured out yet how to keep the ios 3.1 compatibility...
i guess the issue is this: completionHandler:(UIPrintInteractionCompletionHandler)
A block of type UIPrintInteractionCompletionHandler that you implement to handle the
conclusion of the print job (for instance, to reset state) and to
handle any errors encountered in printing.
once i add the block:
void (^completionHandler)(UIPrintInteractionController *, BOOL, NSError *) =
^(UIPrintInteractionController *printController, BOOL completed, NSError *error) {
};
the app won't even launch on iOS 3.1
probably because blocks aren't available there.
yes, i made sure that this code won't be run when launched on iOS 3.1...
if (([[[UIDevice currentDevice] systemVersion] floatValue] >= 4.2) && ([UIPrintInteractionController isPrintingAvailable]))
so i wonder if there's a way to have printing support for iOS >4.2, but keeping it to run on iOS 3.1?
maybe there's a way to use a method instead of the "block"?
or how would be the correct way to have printing available on supported iOS devices, and remain backwards compatible to iOS 3.1?
just add -weak_framework UIKit to the project settings under "Other Linker Flags" and make sure you use conditional code for printing API.
Conditional code should check feature availability, not OS version:
if (NSClassFromString(#"UIPrintInteractionController")){
void (^completionHandler)(UIPrintInteractionController *, BOOL, NSError *) =
^(UIPrintInteractionController *printController, BOOL completed, NSError *error) {
};
}
Set your project target to iOS 3, and you're good to go.
The best practice for detecting if AirPrint is available is to use NSClassFromString. If you use this method in general, then you always know if exactly the class you want is available, without having to hard-code which features correspond with which version. Example code:
Class printControllerClass = NSClassFromString(#"UIPrintInteractionController");
if (printControllerClass) {
[self setupCanPrintUI];
} else {
[self setupCannotPrintUI];
}
That way your app can still work on previous iOS versions, although it won't be able to print from them.
I've been able to use this technique and run it on an iOS 3.0 device without any problems with the block code (the ^-based stuff). In my build settings, I have the Base SDK set to iOS 4.2, and the Deployment Target set to iOS 3.0.
I posted a sample Xcode project at the end of this blog post on printing in iOS. This is the project that successfully runs for me on a device with iOS 3.0 and another device with iOS 4.2. You may have to change the bundle identifier in the info.plist to get the code-signing to work for you, but that's independent of the printing stuff.
Set Deployment Target in your Project Settings to iOS 3.x. However, set the Base SDK to 4.2. Now you can use the 4.2 classes and iPhones running 3.x can install your app too.
Keep in mind that when you use a 4.2 class on an iPhone 3.x, the application will crash (so keep checking the system version on-the-go).
NSComparisonResult order = [[UIDevice currentDevice].systemVersion compare:#"3.2" options: NSNumericSearch];
if (order == NSOrderedSame || order == NSOrderedDescending && [[UIDevice currentDevice]isMultitaskingSupported]) {
// >4.2
}
else {
//< 4.2
}
Note:
also change UIKit framework setting from "required" to "weak" this will help you to run application on iOs < 4.2 as well as iOs >= 4.2
Is ther any way to perform a runtime check for the iPhone device at runtime?
It has to be able to differenciate iPhone 4 from other iPhone/iPod touch models.
Any workaround that does the same thing is OK too.
I use some code like this for the same purpose:
if([[UIScreen mainScreen] respondsToSelector:#selector(scale)])
return [[UIScreen mainScreen] scale] == 2.0 ? YES : NO;
return NO;
Only iOS 4.x+ devices support the UIScreen scale instance method. And since iPhone4's don't run iOS 3, we can rule those out right away. Next, we check if the scale factor is 2.0, if so we know it has a retina display.
While this isn't definitive (apple could release another retina device tomorrow), it does test 'model' where it's important -- i.e., you could be fetching images from a web service that provides #2x images and standard images, which is what I'm doing, which means you need to write the scaling image support manually, you don't get it for free as with UIImage's -imageNamed: for local files.
You can get the exact model through the UIDevice class:
[[UIDevice currentDevice] model]
This, and some other methods are documented here: http://developer.apple.com/iphone/library/documentation/uikit/reference/UIDevice_Class/Reference/UIDevice.html
Be careful, though, to not confuse hardware model with iOS version. If you want to provide extra/different functionality for devices that support them, it's better to check if that specific interface is available, using the respondsToSelector: method, or the NSClassFromString function.
Be careful with using the NSClassFromString function, though, since some classes exists as a part of the private API in the earlier SDK:s, with a completely different interface.
I am trying to create a universal binary that supports multitasking on the iPhone 4 and can still run on the iPad.
I know how to avoid compile errors for different versions of the iPhone IOS by checking if a class exists by using NSClassFromString and "respondToSelector", but is there a way to check for the existence of constants like UIBackgroundTaskInvalid?
I of course can use #IFDEF, but I want to avoid this.
You do it as follows:
if (NULL != &UIBackgroundTaskInvalid) {
//do multitasking stuff here
} else {
// don't do multitasking stuff here.
}
Basically you want to verify that the address of that variable exists.
Update: To be clear, you can't really use an #ifdef for this since you will build with a version of the SDK that contains the symbols.
It's probably sufficient to test for the existence of a method that you know is associated with the constant.
The preferred method to check for multitasking iOS is to see if UIDevice responds to isMultitaskingSupported, like this:
//----------------------------------------------------------------------
// returns YES if multitasking is available (iOS 4.0 or >)
//----------------------------------------------------------------------
BOOL hasMultitasking()
{
UIDevice* device = [UIDevice currentDevice];
if ([device respondsToSelector:#selector(isMultitaskingSupported)]) {
return [device isMultitaskingSupported];
}
return NO;
}
If multitasking is supported then you can use those multitasking related constants, which you should have weak linked to.
Is this the proper way to detect which device a user is running?
NSString *currentModel = [[UIDevice currentDevice] model];
if ([currentModel isEqualToString:#"iPhone"]) {
// The user is running on iPhone so allow Call, Camera, etc.
} else {
// The user is running on a different device (iPod / iPad / iPhone Simulator) disallow Call.
}
It is not a general solution but Apple in many cases provides API calls to check wether specific feature is supported or not. Examples could be:
+isSourceTypeAvailable: and +availableMediaTypesForSourceType: in UIImagePickerController allowing you to check if camera is available for the current device.
+canSendMail in MFMailComposeViewController to check if device is configured to send mail.
-canOpenURL in UIApplication class to check if URL can be opened. For example it can be used to check if it is possible to make a phone call:
if (![[UIApplication sharedApplication] canOpenURL:
[NSURL URLWithString:#"tel://"]])
//We cannot make a call - hide call button here
If such API calls are available for your purpose I would use them rather then rely on hardcoded string identifiers.
I'm not sure I'd want to generalize that much (ie, there may eventually be an iPod with a camera, and I don't know that the iPhone will ALWAYS be called "iPhone"), but yes, this is the accepted way.