Getting your app ready for iOS13 using Xcode 11

Sumeet Kumar Gupta
5 min readSep 13, 2019

--

This post will perhaps be useful for a short duration till all of us have migrated/updated our codebases to build and run smoothly using Xcode 11.

Here is a list of few issues I faced when I tried building my app using Xcode 11 along with how I got around them(some solutions will seem kind of “hacky” but I adopted them so that the app can still be released to the store with minimal impact on User Experience). I am pretty sure there are things which I must have not run into yet, but this should help you save a little bit of time.

1. Default Modal Presentation Style Change

The default presentation style for a UIViewController is now .pageSheet, as opposed to what it was earlier i.e. .fullScreen. We can force the presentation style to be full screen by setting

vc.modalPresentationStyle = .fullScreen

Since the presentation of these controllers defaulted to .fullScreen in iOS 12 anyway, the same user experience would continue in iOS 13.

The right solution however, would be to go to each screen which gets presented, see the use case where it is being presented, see if .pageSheet still makes sense, if not set it to .fullScreen but that would need a lot of effort especially if your codebase is huge.

As a quick fix, I did the following:

UIViewController extension for setting modalPresentationStyle to .fullScreen for all controllers loaded from XIBs or Storyboards

Limitation: There are a few limitations with the above solution

  1. It would not work with controllers which are created via code(I am still trying to figure out ways to achieve that. Do share your thoughts if you have a solution for it)

Workaround to limitation: Assumption here is that most of the ViewControllers the app uses might be created using the Interface builder. So the effort now reduces to going to only those ViewControllers which are not and setting the property for them manually.

N.B.: If you do intend to use other presentationStyle for your ViewController, you can still override the awakeFromNib() method in your ViewController subclass, the awakeFromNib() of the extension gets called before the ViewController’s method, hence the implementation in your subclass would override the above implementation.

2. Swipe to Dismiss

If you do choose to go with the .pageSheet presentationStyle, it would mean that the users can now dismiss the ViewController with a swipe down gesture. You will have to to identify all screens where you want to limit the dismiss of the presented controller unless an action is taken on the screen. This action could be a Cancel or Done button which you need the user to explicitly click in order to have controls before completing the dismiss action(e.g. screens where changes are done and dismiss would mean the changes would be lost, so you might want to show a confirmation alert).

This can be done by setting the isModalInPresentation to true for the presented ViewControllers for which we do not want swipe to dismiss to be enabled.

So building on the solution above, I forced every screen to have a modal behaviour.

UIViewController extension for forcing a modalPresentationStyle for all presented ViewControllers

Limitations and workaround: The limitations and workaround are similar to the previous point, i.e. it will work with only those controllers which are created using the interface builder.

N.B.: Note that the #available attribute adds check for iOS 13.0. if you have multiple members in your team working on the codebase, you will have to ensure that you do not merge this to your root branch unless all the developers have started using Xcode 11, otherwise the check would fail, along with the isModalInPresentation property setting statement.

3. iOS dark Mode

Well as much as we would want our apps to look outstanding in the dark mode, it is possible that it looks quite the opposite on the first run.

Quick fix to making sure the app does not look poor(if not terrible), would be to force the light mode for the app, until you actually revisit each screen of the app and optimize it to look the best in the dark mode.

This can be done by a setting in the apps info.plist file

Forcibly setting interface style to light.

4. Segmented Control Tint

Setting the tint color for the segmented control does not work as before, to set the right tint for the selected state you will need to set the
.selectedSegmentTintColor property of the segmented control.

Sample for demonstrating setting of tint color for Segmented control in iOS 13

5. Changing window’s rootViewController, calls `dismiss(animated:completion:)` method of the previous VC

This was a super weird bug/behaviour I noticed in iOS 13.

In Xcode 11 beta, the dismiss method of the current window’s rootViewController gets called when the window.rootViewController is changed to a different ViewController, this does not happen in the previous versions of iOS.

This behaviour was happening in an app wherein the dismiss(animated:completion:) method was overriden to change the controller to another one(in this case it was a login flow). Now the problem was, when this method was getting called(on successful login) for dismissing the controller, it would internally reset the rootViewController to the home page. This made the dismiss method getting called again(due to the new behaviour) recursively causing the app to crash since it would get stuck in the loop.

Validated it by creating a sample project and the unexpected behaviour is confirmed to be happening with new Xcode and iOS.
Could not find any documentation where this behaviour was explained, So I have raised the issue with Apple (have not received any response yet though). In any case, the solution(more of a workaround) to this problem was to make a separate method for resetting the root on login success rather than overriding the dismiss(animated:completion:) method.

6. The old(widely adopted) way of generating device-token string will not work

If you have been using the following implementation for getting a string from the device token which the `application:didRegisterForRemoteNotificationsWithDeviceToken:` this will start breaking since the implementation of the description returns .

Old way of getting device token string from deviceToken data

Instead use the following:

New way of generating token string with iOS 13

Here are some issues not occurring due to Xcode 11 itself, but issues I faced in the 3rd party SDKs we use:

Update to the latest version of the OneSignal SDK

If you have an integration with Onesignal, you likely would have received an email for this, but if you haven’t you need to update to their latest SDK. The changes they have done on the library are primarily the same as above. Do go through https://onesignal.com/blog/ios-13-introduces-4-breaking-changes-to-notifications/, if you need more info on what changes they made. They also suggest other changes that you might need to at your notification sending backend services(if you use an in-house service for the same).

Crash in older version of the Realm SDK

We were using Realm v3.16.2 in the app which was crashing on iOS 13 due to an internal issue with their SDK. The fix for this was to update the SDK version to v3.17.1.

Crash due to the Firebase SDK

There were issues(random crashes) we were facing due to implementation details of Firebase, they have also been fixing them as and when they were reported by the users. So if you face any issues too, upgrading it to the latest version of Firebase would solve most of them.

So these were some issues I faced while using my app with Xcode 11 and the quick fixes/workarounds I used. I am pretty sure there are more things I will find in due course. Meanwhile, if you find any issues do mention them in the comments. If you have recommendations on how the above workarounds can be further improvised on, please mention the same as well. A shoutout to Sambhav Shah and tabrez pasha for their inputs in coming up with some of the solutions.

Happy Upgrading 🤘.

Don’t forget to leave some claps if you found this post useful 😊

--

--