Possible to implement traitCollectionDidChange in Swift 2 with iOS 7 target?

I have an iOS 9 project with a deployment target of iOS 7.1, using Xcode 7 beta 4. I can't find a way in a UIViewController to override the traitCollectionDidChange method.


I've added this to a view controller:


override func traitCollectionDidChange(previousTraitCollection: UITraitCollection?) {
    // ...
}


The compiler gives the error:


Foo.swift:142:66: 'UITraitCollection' is only available on iOS 8.0 or newer


True enough. The source editor provide two popup suggestions:


Add @available attribute to enclosing instance method.
Add @available attribute to enclosing class.


Suggestion #2 is out of the question (the view controller is needed in iOS 7.1). When clicking suggestion #1, it changes the code as follows:


@available(iOS 8.0, *)
override func traitCollectionDidChange(previousTraitCollection: UITraitCollection?) {
    // ...
}

This leads to a new compiler error:


Overriding 'traitCollectionDidChange' must be as available as declaration it overrides.


I'm able to override traitCollectionDidChange in Objective-C but not Swift 2. Bug? Suggestions?

Answered by mmanni in 37603022

Thanks for your original post, I've just found myself facing the same issue today while converting my project to Swift 2.

Here's a possbile workaround I am experimenting with and that should allow you to keep your deployment target to 7.0:


- Keep your UIViewController (let.s call it ParentViewController) as it is, available for all supported OS versions (don't decorate ParentViewController with @available)

- Silent the compiler by removing the override of traitCollectionDidChange

- Create ViewControllerWithAdaptiveBehaviour as a subclass of ParentViewController and make it override traitCollectionDidChange

- Declare the latter as @available(iOS 8.0, *) to silence the usual compiler's moaning

- At run time, conditionally load ParentViewController or ViewControllerWithAdaptiveBehaviour depending of the OS version at runtime.


This should work, hope it helps

Just guessing from the error message, but it sounds like you need to make the method public, i.e. “as available”.

I think it's a bug in the objC header.


It looks like the UITraitEnvironment protocol (which declares traitCollectionDidChange:) isn't decorated with any availability macro, so the compiler assumes it should always be available even though the UITraitCollection class used for the parameter doesn't exist until 8.0.

Marking the override of traitCollectionDidChange as public would mean that the class must also be public, which would mean its base class must also be public. I can't imagine that module scope would need to be sacrificed to implement a delegate method. It's not the case with other UIKit protocols.

That makes sense. UITraitCollection is marked with @available(iOS 8.0, *) but UITraitEnvironment is not. Hopefully they fix this soon. I've had to update the Xcode project to target iOS 8 in the meantime.

Accepted Answer

Thanks for your original post, I've just found myself facing the same issue today while converting my project to Swift 2.

Here's a possbile workaround I am experimenting with and that should allow you to keep your deployment target to 7.0:


- Keep your UIViewController (let.s call it ParentViewController) as it is, available for all supported OS versions (don't decorate ParentViewController with @available)

- Silent the compiler by removing the override of traitCollectionDidChange

- Create ViewControllerWithAdaptiveBehaviour as a subclass of ParentViewController and make it override traitCollectionDidChange

- Declare the latter as @available(iOS 8.0, *) to silence the usual compiler's moaning

- At run time, conditionally load ParentViewController or ViewControllerWithAdaptiveBehaviour depending of the OS version at runtime.


This should work, hope it helps

Good idea. This works around the issue. I was hoping Xcode 7 beta 5 would fix this but no luck.

Glad it helped, and yes it looks the bug is still there so we may have to stick to this workaround to support iOS7 until a fix comes in.

Unfortunately not fixed in Xcode 7 GM seed.

Unfortunately not fixed in Xcode 7 GM seed.

Bummer.

Did you file a bug about it? If so, what’s the number?

Share and Enjoy

Quinn "The Eskimo!"
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"
Possible to implement traitCollectionDidChange in Swift 2 with iOS 7 target?
 
 
Q