App migration between different iOS versions - ios

Currently, I'm in the middle of adapting my app for iOS 7.1 to support iOS 8.
During this process, it dawned more and more on me that I may have seen the relationship between SDKs and OS versions wrong all the time.
I'll tell you with a concrete example:
The UIViewControllerContextTransitioning protocol gained some more methods for iOS8. So in order to support the new OS, I started implementing the new methods in my ContainerViewController.
When I came across the - (UIView *)viewForKey:(NSString *)key method, I naturally checked the key against the UITransitionContextFromViewKey constant.
This constant has the NS_AVAILABLE_IOS(8_0) suffix. So I assumed the constant is only available when running on iOS8 and above.
When I set the deployment target in Xcode from 8.0 to 7.1 and hit 'Build & Run', to my surprise there was no error at all and the app ran on my iOS7.1 device without any problem. - Even while the code contained the constant that should only be available at >= iOS8.
So here are the questions that came to my mind at this point:
The NS_AVAILABLE_IOS(8_0) suffix in the header files does not determine the iOS version, but rather the SDK version from which on the marked API is available. - is that correct?
Does this mean we are able to use APIs added in the iOS8 SDK in apps that are compiled for iOS7.1, as long as we use the new SDK to build the app?
I'm particularly curious about the second question, because that would mean we can use cool new stuff like the UIVisualEffectView for apps that run on iOS < 8. Also, this would mean much less headache for example when maintaining CoreLocation functionality while following all the changes made to it (kCLAuthorizationStatusAuthorized -> kCLAuthorizationStatusAuthorizedWhenInUse, etc.), because we can simply maintain a single code base and do not have to #ifdef a lot.
Please tell me if my assumptions are correct and if not, please correct them in your answer.
Thank you!

It's important to realize that linking against the iOS 8 SDK with a deployment target of iOS 7 allows you to create an application that will run on both, but there will be differences in API availability.
When the application is run on iOS 7, iOS 8 APIs will be unavailable. At runtime, acccessing an iOS 8 API can cause a crash or other undesirable behavior. The recommended way to handle this is when using classes, methods, or constants that are marked as available only on iOS 8 or later, you must query for their availability at runtime.
In the case of new UIViewControllerContextTransitioning methods, you would query for the presence of those iOS 8 methods at runtime:
if ([transitioner respondsToSelector:#selector(viewForKey:)]){
// It's available, you're set to call it
} else {
// The method is not available, you will have to work around it.
}
Obviously, this can complicate things significantly for some applications. The application DeployMate can be very useful for finding API disparities in your code base. It will scan your project and tell you where you are using a method that is iOS 8 only.
Guidance for supporting different SDK and OS versions and capabilities is explained in more detail in the iOS 7 Tech Talk Architecting Modern Apps, Part 2. While the examples are for supporting iOS 6 and 7, the guidance here applies to supporting more than one OS or SDK, no matter what the version.

Related

Xcode How to check if there is any API used in the whole project which is not available for the current development target

Recently my app was getting crashed on IOS8 because i have used an API which is only available for IOS 9 and above. I am wondering is there anyway to check the whole project and find out if I am using any API which is not available for the current development target. Something like the warnings for the deprecated APIs. Thanks.
In order to tell the compiler you want to support an earlier OS, you need to set the SDK to that earlier OS's SDK. If you set the SDK to iOS 8, then any time you use functionality from a later OS, you should get a compiler error.

deprecated in iOS 9, compatibility?

I've upgraded my Xcode project with Xcode 7. I'm using Objective-C.
When I'm targeting iOS 9.0 in deployment target, I've 36 warnings :
UIAlertView is deprecated, use UIAlertController.
ABAddressBookRef is deprecated, use CNContactStore ...
setStatusBarStyle:animated is deprecated, use [UIViewController preferredStatusBarStyle]
and some other...
Well, I would like to keep compatibility with iOS 9 and at least iOS 8.
Do I have to disregard these warnings for keeping compatibility with different OS ?
If I use UIAlertController iOS 8, is it working ?
What the best thing I've to do ? Using deprecated or replace with new code ?
If you are no longer targeting the older versions of iOS then its recommended to update deprecated code. You don't absolutely have to though, deprecated methods are still officially supported in Apple's SDKs, but one day Apple may remove those methods.
Here's what Apple says about deprecation:
From time to time, Apple adds deprecation macros to APIs to indicate
that those APIs should no longer be used in active development. When a
deprecation occurs, it is not an immediate end-of-life to the
specified API. Instead, it is the beginning of a grace period for
transitioning off that API and onto newer and more modern
replacements. Deprecated APIs typically remain present and usable in
the system for a reasonable amount of time past the release in which
they were deprecated. However, active development on them ceases and
the APIs receive only minor changes—to accommodate security patches or
to fix other critical bugs. Deprecated APIs may be removed entirely
from a future version of the operating system.
As a developer, it is important that you avoid using deprecated APIs
in your code as soon as possible. At a minimum, new code you write
should never use deprecated APIs. And if you have existing code that
uses deprecated APIs, update that code as soon as possible.
Fortunately, the compiler generates warnings whenever it spots the use
of a deprecated API in your code, and you can use those warnings to
track down and remove all references to those APIs.
https://developer.apple.com/library/ios/releasenotes/General/WhatsNewIniOS/Articles/iOS7.html
"Deprecated" means at least one of the following:
This API isn't gone yet, but it might be in the future, or on future platforms/technologies. For example, all API deprecated before iOS 8 is unavailable in Swift.
There's a better alternative to this API, and the old one might not keep doing everything you need as the platform changes. For example, AssetsLibrary is still around even though it's deprecated, but it doesn't provide access to iCloud Photos or Live Photos — for those you need its replacement the Photos framework.
Those are things to consider when targeting an OS version where the API are deprecated.
However, deprecation warnings are based on your project's minimum deployment target. If you tell Xcode that you want to build for iOS 7 and newer, you won't see warnings for APIs that are deprecated as of iOS 8 or iOS 9.
If you want to deploy back to an older minimum OS target, but use features from a newer OS, you need to put availability checks in your code that uses the newer features. See Apple's docs on compatibility/availability and weak linking in general, and/or Checking API Availability for Swift.

How does an app with lower base sdk work?

In XCode I can specify Base SDK. I am wondering how does that work behind the scenes? If I am running an app, for example, on a device that has iOS 7 and my base SDK is iOS 6, then how come the app has the old 'look and feel'? Does XCode compile the older SDK and include it within my app or does new version of iOS comes with older libraries/SDKs?
In other words, does the run time know this app is compiled with lower base SDK and somewhere in UIKit's code it does:
if (lower SDK) {
//show old look/feel
} else {
//show new look/feel
}
or does the app itself include the old library and load it ?
Thanks
iOS applications are forward compatible with new versions of iOS. The reason is :
Almost all changes to the iOS versions are additive and hence an
application build using lower version still runs on the higher iOS
version.
Though, we need to take care of this point:
As frameworks evolve through various releases, APIs are introduced or
deprecated and behaviors of existing APIs may occasionally change.
Apple makes every effort to minimize changes that may cause
incompatibilities, in some cases providing alternate behaviors based
on the framework version. In rare cases, your code needs to determine
the framework version and adjust accordingly
To understand more, read this
Apple never changes / deletes / renames classes or methods. They only add new ones.
If they don't want you to use it anymore, they mark it as deprecated.
This is a very important point.
At compile-time, the compiler checks if all classes and method signatures are available in the SDK your building your app with.
If that's the case, you can build and deploy your app. Because those classes and methods will never be deleted from newer versions of the framework, your app will run just fine.
On the other hand, you can build apps and deploy them to systems, which do not actually support the current SDK. For example, you can use Autolayout (NSLayoutConstraint class is available since 10.7) and deploy it for Mac OS X 10.6. The compiler will not say a word.
The app will crash though on systems prior to 10.7.
You should set your target to ios 5.0 (via your project target settings) for making sure that none of the ios6 methods are used (or else a compilation error will prevent you from building it).
In order to support new features and check if ios6 is available on the device you have two ways :
During compilation (so you can still build your app with lower targets and newer together) use the following macro
#if __IPHONE_OS_VERSION_MIN_REQUIRED > __IPHONE_6_0
// Your ios6 code goes here
#endif
2: During runtime : [[[UIDevice currentDevice] systemVersion] floatValue] > 6.0
Your project is built against the Current SDK. If you have an older Deployment Target, then your code base is compiled against that. So if you are building against 7.0, but have a 6.0 deployment target, iOS 7 specific deprecations will not be triggered. Everything will be compiled against the oldest specified deployment target.
This will however put the pressure on you as a developer to make sure you are not using iOS 7 specific code. The compiler will still assume you mean to allow newer users to run your application as well and that all the newest methods are available to you and your latest version users. You can either test your code base against the older SDK with older devices or Simulators to make sure it runs well, or use an application like Deploymate that will test for methods you are using that could potentially cause problems.
If you plan to use any of the latest methods, you will need to wrap them up in the compiler if statement (like Peter Fidemraizer answered) or in normal if statements checking the version in the Foundation framework.
if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_6_1) {
// Load resources for iOS 6.1 or earlier
} else {
// Load resources for iOS 7 or later
}
Base SDK means, the SDK that your app is going to be built on. SDK's have some frameworks etc. that are differantiated as the version of the SDK changes. For example;
Let's say your current Base SDK in your XCode is iOS 6:
You can have the frameworks and feautres that iOS 6 SDK provided you to.
Your app will be usable in any iOS SDK that you specify as "Minimum iOS SDK". Minimum iOS device gives you some restrictions on components to use. be aware of that.
Your app will be usable in iOS 7 too, just like it works in iOS 5 or iOS 6. Because iOS versions have backward compatibility. That means, iOS 7 will run the apps that are running in iOS 6 too.
Let's say your current Base SDK is iOS 6 and you want to make it iOS 7
Your app will be built with a brand new SDK, so, if the new SDK has
some big changes in it, you will see the differences immediately when
you run the app. For example, in iOS 7 SDK, you can use status bar
(20 px) as a view component too. That may ruin your view hierarchy.
You need to test your app again to check that your code is compatible with iOS 7
If you want to use new iOS 7 frameworks or features, you are in the correct way, you can use them now :)
In short, Base iOS SDK is on what iOS version your app is compiled & built on. running it on a iOS X? device is a different concept.
Hope this helps
Base SDK is the SDK that you want to use to build the app. Use "Deployment target" to specify the minimum OS you want your app to run on.
If you want to know the iOS version, check out this question.
While updating the Apple frameworks itself,Apple takes care of support for multiple iOS versions;However you need to follow some basics checks, which are explained here

MonoTouch: Approaching Obsolete iOS methods

As iOS is upgraded the signatures and methods of older versions get marked as obsolete by MonoTouch.
My question is, if we take the suggestion for a new method that MonoTouch offers , will we be negatively affecting older iOS versions?
I understand that new features, such as Facebook in iOS 6 are not available in 4.3, but this question is more about migration for MonoTouch apps to higher versions of IOS while keeping compatibility.
For example:
An iOS 4.3 device running a MonoTouch 6 app : Will removing obsolete methods and replacing them with the new ones work still ?
There's no single, general, answer as it depend why the method/type was obsoleted.
Most [Obsolete] attributes have a message stating why you should avoid them. They mostly fall in two groups:
There was a binding error in the API, e.g. a typo. A new API was added to correct this (and its name should be part of the description). In this case there is no problem, for a 4.3 device, to use the new API added in MonoTouch 6.x;
Apple introduced a new API and deprecated the use of an older one. In this case the description should state the new API and the iOS version where it applies. You should not use the new API (e.g. anything added in iOS 6.0) if you wish to target older devices (e.g. 5.x).
If you find [Obsolete] method/types without any text message or when the text is not clear enough to allow you to make a clear decision please file a bug report so it can be corrected.
This may help in testing. Add old iPhone Simulators:
open xcode and in the top menu go to xcode >> preferences >> Downloads and you will be given the option to download old sdks to use with xcode. You can also download command line tools and Device Debugging Support.
This will let you go to the simulators Hardware/Version menu and choose 4.3 or 5.0 or 5.1 etc.

Updating apps to iOS6

Haven't been able to find an accurate response to this question on Apple Developer forums.
As with other Apple Developers, I will upgrading our apps to support iOS6 devices.
I've downloaded XCode 4.5 which supports iOS6 SDK.
I understand I cannot submit versions of my app to the app store using this XCode build, however:
if I re-compile and build an app using the deployment target of 6.0 and fix all the known issues e.g. deprecated methods etc. when Apple releases GM for iOS6, will any build compile and work with iOS5 devices as well?
Should I just be submitting apps with a deployment target of 5.0 or will those fail to run in iOS6?
Should my deployment target only be iOS6 if I am using new iOS6 features?
(confused).
Since this is a pretty generic question about supporting multiple versions of iOS and does not cover any iOS6 specific things (covered by NDA), here goes my answer:
if I re-compile and build an app using the deployment target of 6.0 and fix all the known issues e.g. deprecated methods etc. when Apple releases GM for iOS6, will any build compile and work with iOS5 devices as well?
In principle, yes, it will, provided you have not used any iOS6-only feature or you did it properly (see the answer to your third question). However, testing against an actual device running iOS5/4 (or the simulator) is almost mandatory if you want to be sure that things work correctly.
There is also a chance that something that is currently working under an older iOS version will just break on iOS6 (this can happen in case some bugs were added, but also in case some bugs were fixed and it happens that your code had a bug of its own that countered the effect of the former). So, testing is the king. (Thanks to rsswtmr's comment about this).
Should I just be submitting apps with a deployment target of 5.0 or will those fail to run in iOS6?
You can specify a deployment target of 5.0 if your app does no use any iOS6-only feature (or you do it properly, read later); in other words, this setting will not break compatibility with iOS6;
Should my deployment target only be iOS6 if I am using new iOS6 features?
It can, but it is not the only way.
If you specify your deployment target as iOS6, then you can freely use any iOS6-only feature in your app without concern. The app store mechanics will prevent your app from being installed on any older device and you will be safe.
On the other hand, if you specify your deployment target as iOS5 or older, then you can still use any iOS6-only feature in your app, but you should properly support older versions of iOS by "guarding" any usage of iOS6-only features and providing a fallback for iOS5.
This means the following: say that you are going to use featureA only available on iOS6; what you can do is:
check to see if the feature is available at runtime (e.g. class respondsToSelector, etc);
guard your code within an #ifdef so that it will be compiled only on when possible;
if the check at 1. will fail, define a way out for older iOS versions.
Have a look at this post on supporting multiple iOS versions.
Set "Base SDK" to Latest iOS and "iOS Deployment Target" to the older version you plan to support (iOS 5.0 for instance).
Add conditional code to use feature available in latest iOS without crashing in the old one supported.
The section "Conditional Coding" in this Apple guide can be helpful. Also check other questions on the subject in SO.

Resources