An iOS7 and iOS8 simple alert

来源:互联网 发布:上瘾网络剧在线看 编辑:程序博客网 时间:2024/06/03 14:18

http://coding.tabasoft.it/ios/an-ios7-and-ios8-simple-alert/

In iOS8 the code to show a simple alert to the user is completely changed. UIAlertView is now deprecated:

alert deprecated

The new class is UIAlertController and it is not complex to use (more in a minute). But we also want to support our iOS7 users, so wouldn’t it be nice to have a single class handling the different code? This is what we are going to create in this post.

The old way

To show a simple alert with an “OK” button in iOS7 we use this code:

Then we conform our class to the UIAlertViewDelegate protocol and add the method:

This method is called when the button “ok” is pressed. Very simple code and the result is:

ios7alert

This code works right in iOS7 and iOS8 (but it is deprecated in iOS8).

The new way

The new way to do this is in iOS8 is to allocate an UIAlertController, add to it an action relative to the button “OK” and then present the controller using presentViewController.

The result is identical to the previous:

ios8alert

Two notes about the iOS8 code:

  • If you run it in iOS7 you cause a crash, so this can be used only if your running device has a system >= iOS8
  • A curiosity: in iOS7 you could show an alert from inside viewDidLoad. Now, if you try this, you get a message in the console “Warning: Attempt to present <UIAlertController: 0x7fb219733510> on <ViewController: 0x7fb2196625d0> whose view is not in the window hierarchy!” and nothing happens. It seems that the alert is now a controller and the controller hierarchy is not yet ready. I think this is not a problem and you should not show an alert from viewDidLoad anyway. I showed the alert from the viewDidAppear method.

A single multi-system Alert object

Now we want to create our class that hides the different implementation from our app.

Let’s call it SevenEightAlert. We will invoke it with the common code:

The implementation

In our class we ask for the current version of the system using UIDevice.currentDevice().systemVersion and execute different code depending on it:

Note that for iOS7 we save the closure passed as the third parameter in a property in order to use it later, in the alertView method of the UIAlertViewDelegate.

This code works perfectly on iOS8: we see the alert, press OK and see the log in the console (“alert dismissed”) and the alert disappear graciously.

But when we run it on iOS7 the app just … crashes (with a bad SIGABRT signal). Why?

Alert is Asynchronous

In viewDidAppear we create an instance of SevenEightAlert (calling SevenEightAlert()), then we call show on it and exit from the function. At the time the closure is called (when we press back, some seconds after) that instance does not exist anymore. But that instance was also the delegate of our UIAlertView (remember “delegate = self”) so the app crashes trying to call a delegate object that does not exist anymore.

Not a simple problem, we should try to extend the life of that instance more after the method viewDidAppearreturns. How we can do this?

Welcome the associated object

In iOS we can associate an object to another object.

This is a feature of the Objective-C 2.0 runtime, useful when we want to add a property to another object (of which we don’t have the code), something we cannot do with a category (or swift extension).

To read more about associated object start from this apple document.

If we use associated objects we also extend the length of the life of the object we attach to the length of the life of the object attached (as if it would be a property).

To use associated object we must extend NSObject (because it uses theObjective-C 2.0 runtime).

In the SevenEightAlert.show method, if the system is <= 7 and the action is not nil, we associate ourself to the calling view controller using the objc runtime function objc_setAssociatedObject:

Having declared the two properties:

(assocObjectHandle is simply a key we use as a reference of the association)

We then remove the association after the closure execution in the delegate’s alertView using objc_setAssociatedObject:

And now the code works right also for iOS7 and the callback action is called when the user press “OK”.

ios7-8alert

You can find the complete code of the class in the GitHub project SevenEightAlert.

And, as usual, if you have comments please feel free to contribute.


0 0
原创粉丝点击