Was I supposed to get a warning [duplicate] - ios

This question already has an answer here:
Why is the Xcode compiler not warning me about invalid methods for my Deployment Target?
(1 answer)
Closed 9 years ago.
In my code I use
[[self presentingViewController] dismissViewControllerAnimated:YES
completion:dismissBlock];
The thing is my deployment target is set to: 5.0.
While base SDK is 6.1.
Was I not supposed to get a warning by XCode? (because I think the above method got introduced in iOS6).

Unfortunately no, Xcode doesn't check if you use symbols that are not available in your deployment SDK.
It only checks your code against the base SDK.
But you can use some third-party software for this, like DeployMate.
That being said, as others pointed it out, dismissViewControllerAnimated:completion: is available since iOS 5, so your code is safe.
But it's always a good idea to check for unavailable or deprecated APIs in your app, using something like DeployMate.
EDIT
Here's an answer to your comment:
If you deployment target is 5.0 and your base SDK 6.0, using a symbol available in the 6.0 SDK on an iOS 5 device will crash the application.
But Xcode won't warn about this when compiling, hence the need of some third-party software.
Once you identified the problematic symbol, using respondsToSelector: is the way to go, as it's better than simple version checking.
This way, you can have conditional code that will run with both SDK versions:
if( [ someObject respondsToSelector: #selector( someIOS6Method ) ] )
{ /* iOS 6 code */ }
else
{ /* iOS 5 code */ }
Only do this if you have detected SDK issues. Don't do this for everything.

According to UIVIewController class reference, this method is available from iOS 5.0 and higher.
Availability
Available in iOS 5.0 and later.

It is not ok to warn you. It doesn't have this warnining included in the default bundle of the SDK.

Related

What happens if I use LAPolicyDeviceOwnerAuthentication on iOS 8?

In my app, I would like to know if the user has setup a passcode or fingerprint (touchID). There's a pretty easy method just for that: [LAContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthentication error:error].
However, Apple's docs say LAPolicyDeviceOwnerAuthentication is only available on iOS9 and above. I would rather not crash iOS 8 users without explanation, even if it is getting older. The thing is, I've tried it on an iOS8.4 simulator, and it seems to compile and just work.
What ill effects can happen if I use LAPolicyDeviceOwnerAuthentication on iOS 8?
I use code similar to this:
LAPolicy localAuthPolicy = LAPolicyDeviceOwnerAuthenticationWithBiometrics;
if (![[UIDevice currentDevice].systemVersion hasPrefix:#"8."]) {
localAuthPolicy = LAPolicyDeviceOwnerAuthentication;
}
This ensures I only use LAPolicyDeviceOwnerAuthentication on iOS 9 and later.
It's undocumented what actually happens on an iOS 8 device when you attempt to use LAPolicyDeviceOwnerAuthentication. It's very unlikely anything will crash but the authentication may return NO due to an unknown value or it may succeed because iOS 8 only had one valid value and it may not do any checking.
Unfortunately Objective-C doesn't provide any runtime checks for valid enum values like you can do with constants, methods, and classes.
If you use LAPolicyDeviceOwnerAuthentication on anything below iOS 9, the app will crash. That is what happened to my app when I didn't realize that this was not available on anything below iOS 9, but my app supported iOS 8.x as its minimum supported OS version.

How to define code for different iOS versions

I am working on an iOS app. I want it to support iOS 7 and 8. It is going pretty nicely, however there are lots of different parts of the app which use Apple APIs. Some of these APIs work in both iOS 8 and 7. However, some of them are deprecated in iOS 8. So I therefore went to the Apple developer site to see what to replace them with (new methods/etc....).
However, I now have the problem that the app will work on iOS 8 fine, but certain parts of it don't work properly on iOS 7 as I'm trying to use an iOS 8 API...... (lol).
So I just wanted to know, what is the best way to implement code which works on iOS 8 and 7. I had a few ideas (below), but I'm not sure which is best:
IDEA 1
Whenever I have code which doesn't work on both OS's, I use an if function (which calls a macro) like so:
if (SYSTEM_VERSION_LESS_THAN(#"8.0")) {
// iOS 7 device. Use iOS 7 apis.
}
else {
// iOS 8 (or higher) - use iOS 8 apis.
}
IDEA 2
I was thinking about using ifdef definitions all around the app like so:
#ifdef __IPHONE_8_0
// iOS 8 code here....
#else
// iOS 7 code here....
#endif
Which way is better? I would have thought that the second idea is much faster and uses less resources right?
Or are both my ideas rubbish? Is there a much better way about solving this problem?
Thanks for your time, Dan.
I don't suggest checking the Version and writing code based on that. Instead you need to check whether that API is available or not.
For checking a class available or not:
Class checkClass = NSClassFromString(#"CheckingClass");
if (checkClass)
{
// Available
}
else
{
// Not Available
}
If you need to check a feature/function available;
if ([checkClass respondsToSelector:#selector(yourMethod:)])
{
// Feature/ Method Available
}
else
{
// Feature/ Method Not Available
}
NOTE:
Deprecated API's doesn't mean that you shouldn't use that in current version. It means, it won't work from next version onwards, and only work till current version.
The ifdef-way won't work, because preprocessor statements are evaluated at compile-time; but only at runtime we know which ios-version we have to deal with.
You would use macros for example if you wanted to support Mac OS X and iOS with the same code, because you know at compile-time if the binary will be for Mac OS or iOS.
So you need in this case approach 1 - or, even better, you should use respondsToSelector: to check for availability instead of testing the iOS version if possible.
However, because you are only dealing with deprecation warnings, you don't have to do anything and should simply continue using the deprecated APIs until the app no longer needs to support ios7.

TWRequest class. What to do?

I update the project, which was written under iOS5. Now do support only iOS7.
The project has check:
if ([TWRequest class]) {
...
}
XCODE says "TWRequest is deprecated: first deprecated in iOS 6.0". I know I should use Social.framework.
Therefore, the question whether it makes sense to update these checks, or you can simply remove it? Indeed, in the iOS still supported by default Social.framework?

How to detect if I am accessing iOS6-only methods? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Is there a way for XCode to warn about new API calls?
I'm building an app that will support iOS 4.3 through iOS 6.x. However, I unknowingly used a method that is marked __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_6_0). This means that the selector does not exist in previous versions of iOS.
Of course, when I tested my code on an iOS 5.x device, the app crashed. I figured out what was going on, and inserted a respondsToSelector check, and default to the "iOS 4.x way" of doing things when it fails this check.
How can I prevent these bugs in the future? Is there a compile-time way to figure out that I am accessing iOS-6-only methods, so that I can add appropriate iOS feature-checks?
I don't want to accidentally ship a product that works fine on my iOS6 devices, only to have it fail on someone's iOS4.3 device, because the selector does not exist.
The answer here worked for me: https://stackoverflow.com/a/8919108/208989
Download this header: https://github.com/mattjgalloway/MJGFoundation/blob/master/Source/Utilities/MJGAvailability.h
And put the following at the top of your .pch file:
#define __IPHONE_OS_VERSION_SOFT_MAX_REQUIRED __IPHONE_4_3
#import "MJGAvailability.h"

Developing apps for multiple iOS version

I am testing an app on an iPhone 4 with iOS 5.1 and an iPad 4 with iOS 6.0. I looked around and surprisingly did not find similar questions:
1- My app has some methods that have been deprecated in iOS 6.0 so I believe I have to build some if/then conditions to test for system version using: [[UIDevice currentDevice] systemVersion], and then use the version appropriate methods. Is that the most efficient way?
2- My understanding is, with only one target, the "project" Deployment Target and the "Targets" deployment target serve the same purpose. And I need to have one of them or both as iOS 5.1 since that is the minimum iOS supported. What is confusing is that if the target is built based on iOS 5.1, how would it run on the iPad4 with iOS 6.0:
Does the iPad OS checks for target versions before running or just tries to run the code and it happens that the iOS 5.1 target does not have any code that the 6.0 is incompatible with?
Even if that is the case though, how could a 5.1 target support 6.0 methods that I built to conditionally replace deprecated methods?
Many thanks!
Deprecated methods
Deprecated methods can be used if you are targetting iOS versions that were released before those methods were deprecated. But assuming your deployment target is set correctly, you won't get any compiler errors unless those deprecated methods were always deprecated for the versions you are targetting. In other words, if you are seeing deprecation warnings in your code you need to fix them or check that your deployment target setting is correct. Do not ignore them!
Xcode setting levels
You mention the fact that you can define the deployment target setting at both the target and project level. Xcode build settings at the target level will override project settings. So define the deployment target at one of these levels only, then go to the other and hit delete so you don't have duplicate values. If you only have one target then it doesn't really matter if you define it at the target or project level.
Backwards and forwards compatibility
Finally, there are many factors that come into play for backwards and forwards compatibility. Sometimes there will be new iOS 6 methods like supportedInterfaceOrientations which will simply be ignored on older iOS versions. Other times you need to add explicit checks:
If you are calling a method on an object and that method was only introducted with iOS 6, you will need to add a respondsToSelector: check like this:
// only available on iOS 6
if ([locationManager respondsToSelector:#selector(pausesLocationUpdatesAutomatically)]) {
locationManager.pausesLocationUpdatesAutomatically = YES;
}
If you want to check if a particular class exists on the current iOS version, you can check the return value of the +class method like this:
// Only available on iOS 6
if ([UICollectionView class]) {
// ...
} else {
// class doesn't exist in this iOS version
}
If you want to check if a particular function is available, do a simple if statement on it:
// Only available in iOS 6
if (ABAddressBookCreateWithOptions) {
ABAddressBookCreateWithOptions(...);
} else {
ABAddressBookCreate(...);
}
Finally, if you want to check if a constant is available, check it's address:
// Only available in iOS 4
if (&UIApplicationProtectedDataDidBecomeAvailable) {
// subscribe to notification
}
Your Base SDK setting should always be set to "latest".
If you follow all these guidelines you will be able to solve most of your problems without having to add explicit version checks. Checking the iOS version or device ID is very brittle and is likely to cause your app to break in future versions. You really want to avoid it.
You can use [[UIDevice currentDevice] systemVersion] to detect the OS version, that would work. Rather than detecting the OS version, you could use respondsToSelector: to see what methods are present, NSClassFromString() != nil to see if classes are present, and fallback if that method is not available.
iOS is backward compatible, so iOS 6 will run iOS 5 apps just fine. However, if you want to use iOS 6 specific feature but still support iOS 5.1, you have to :
Compile using the 6.0 SDK so that the compilers knows new APIs
Set your target version to the lowest supported, aka. 5.1. Any system higher than that number will run the code. Any lower will not try.
Use one of the method described in 1. to make sure that each device execute codes the OS support.
I hope that's clear, don't hesitate if you have more questions
What you must do is detect functionality, not iOS version, please check out this thread:
Conditional support of iOS 6 features in an iOS 5 app
You shouldn't check against the system version but rather check against the functionality you are trying to use. On that note remember that deprecated does not mean removed so whatever you are trying to do may very well be there for iOS6. To check against a specific functionality you would do something like:
if([TheClassInQuestion class] != nil)
{
//use it
}
iOS is backwards compatible. If you compile your app for iOS 5.1 it will be perfectly run on iOS 6 as well. No need to re-implement deprecated classes.
But if you change your deployment version from 5.0 to 6.0, Xcode will show you warnings if you use deprecated methods
If you want to use methods, which are available only in iOS 6, you can use this check:
if ([self respondsToSelector:#selector(doSomething:)]) {
[self doSomething];
}

Resources