Testing iOS Apps on IPv6 Networks

Have you ever gotten this message from App Review?

Performance – 2.1
We were unable to review your app as it crashed on launch. We have attached detailed crash logs to help troubleshoot this issue.

Next Steps
Please revise your app and test it on a device while connected to an IPv6 network (all apps must support IPv6) to ensure it will launch without crashing.

The App Review Team regularly rejects apps that fail on IPv6 networks. Some of the time this feedback is a false positive. The app may have crashed for reasons unrelated to networking, but because it happened to crash while connected to an IPv6 network this is the feedback you receive. It is up to you to diagnose the source of the crash.

Some of the third party libraries you are using may not be compatible with IPv6 networks. For example, some analytics companies have provided SDKs in the past which crash randomly on IPv6 networks.

Another common culprit is any of the “reachability” libraries out there. The problem is not always the library itself but how it is used – your app should not try to check for network availability before a network request, and it should not use IP addresses.

So how do you test on an IPv6 network?

Continue reading “Testing iOS Apps on IPv6 Networks”

Safely Using Objective-C From Swift

A common source of bugs in languages that have reference types is the unintentional sharing and modifying of references by different parts of a program. Often this creates side effects in one part of a program caused by innocent changes to values elsewhere – definitely something you want to avoid.

“Defensive copying” is a technique that prevents these side effects by working on copies of references. This prevents the kind of sharing and mutation that causes problems. Defensive copy is a best practice in many languages like Objective-C and Java.

Swift makes and explicit distinction between reference and value types. Classes are references, while structs, enums, and tuples are value types. When a new value is assigned to a struct Swift creates a new instance with its own copy of the data. This copying takes defensive copy and automates it for value types.

Apple talks defensive copy and Swift in depth both in the Swift documentation and the WWDC session Building Better Apps with Value Types in Swift from a few years ago.

But that is only for value types. Chances are that much of your app isn't pure Swift – it's Swift talking to Objective-C. When you are using Apple frameworks like UIKit, CoreData, UserNotifications and many others your Swift code is talking to Objective-C behind the scenes.

When you are working with Objective-C objects it is still important to use defensive copy.

For example, this method is returning a UNNotificationContent object:

func makeContent() -> UNNotificationContent {
let content: UNMutableNotificationContent = UNMutableNotificationContent()
content.title = "Title"
return content

It's actually returning a subclass, UNMutableNotificationContent. That subclass is mutable and could very well pose a problem. The instance could be passed into the user notification center wrapped in a request. It may wait quite a while to be delivered – while your app then modifies that object. It may be intentional, it may be a mistake, either way it is asking for trouble.

The right way to write that method would return an immutable copy of that instance:

func makeContent() -> UNNotificationContent {
let content: UNMutableNotificationContent = UNMutableNotificationContent()
content.title = "Title"
return (content.copy() as! UNNotificationContent)

Let's break down that last line of code.
UNNotificationContent and UNMutableNotificationContent support NSCopying, which allows us to call copy() on it. copy() will return an UNNotificationContent with the same data as the original object – giving us an object that can't be changed later. In Swift the return type of copy() is interpreted as Any, so it must be cast to the correct type.

In your code look for places where you might be doing something like this – particularly where you are later passing objects to code you do not control. You might be surprised how many bugs doing this can fix.