Today I was migrating a project to Swift 4.2 and encountered a quite bizarre issue. As it turns out, you can’t call the
setCategory(_:) method on an instance of
AVAudioSession in Swift 4.2 – the method was mistakenly marked as unavailable in this version of the language (and radars were filed).
This can be a problem if your project targets iOS 9 or older, as the only alternative method
setCategory(_:mode:options:) is available for iOS 10 and above.
Objective-C to save your day!
Fortunately, the problem can easily be solved using Objective-C. You even have options here:
- You can create an Objective-C category for
AVAudioSessionclass and add a method that would call the
setCategory:error:method, which is the objc counterpart of
setCategory(_:). Just don’t forget to import the category in your bridging header.
- You can call
perform(_:with:with:)method. Like so:
let selector = NSSelectorFromString("setCategory:error:")
let category = AVAudioSession.Category.playAndRecord
AVAudioSession.sharedInstance().perform(selector, with: category, with: nil)
This solution works because of the dynamic method resolution provided by the Objective-C runtime.
NSSelectorFromString(_:) takes a method name as a string and returns a selector that was registered with the runtime system. This allows us to bypass the compile-time check for the method’s availability. And the
perform(_:with:with:) method lets us send messages that aren’t determined until run-time.
To conclude, even though simple solutions for the issue were found, it still left me wondering how this silly mistake could make it to the production versions of Apple’s SDKs. 🤔