Using methods marked "unavailable" in swift 4.2

It might be not strictly "on-topic" for this forum (sorry), still, I wonder if there is a way to access a functionality that was present before swift 4.2, but now is missing.

I used to have this piece of code working fine before trying swift 4.2:

if #available(iOS 10.0, *) {
  try session.setCategory(.playAndRecord, mode: .voiceChat, options: [.defaultToSpeaker, .duckOthers])
} else {
  // the following line is now "unavailable", hence there is no way to support iOS <10 with swift 4.2
  try session.setCategory(.playAndRecord, with: [.defaultToSpeaker, .duckOthers])
  try session.setMode(.voiceChat)
}

But now the else branch is failing since session.setCategory(_:with:) has been removed from swift 4.2. The error message, in its entirety, is:

'setCategory(_:with:)' is unavailable in Swift

So my question is, is there a way to access a function which was available in swift 4.1 from a swift 4.2 project? And if not, does it mean that having an API which relies on iOS <10 methods like AVFoundation.AVAudioSession.setCategory(_:with:) above precludes me from using swift 4.2?

Thank you.

This is an issue with AVFoundation in Xcode 10's SDKs, tracked by rdar://problem/42023905. You can work around it by writing an Objective-C function that calls through to the old API, since they're still available in Objective-C. Sorry!

5 Likes

This issue is still present in the GM. Should I expect it to be fixed soon?

1 Like

Still broken as of the official release, so I assume it's not getting fixed any time soon.

1 Like

Just encountered this issue myself as well. I hope it will be fixed in next update.

Sorry for the basic question, I'm a total newbie with xcode: how can someone create an Objective-C function to replace the setCategory function in Xcode?

There are many ways to do this, but here’s what I’d do…

First create an Objective-C class that implements a method that calls through to -setCategory:withOptions:error::

// AVAudioSessionPatch.h

@import AVFoundation;

NS_ASSUME_NONNULL_BEGIN

@interface AVAudioSessionPatch : NSObject

+ (BOOL)setSession:(AVAudioSession *)session category:(AVAudioSessionCategory)category withOptions:(AVAudioSessionCategoryOptions)options error:(__autoreleasing NSError **)outError;

@end

NS_ASSUME_NONNULL_END

// AVAudioSessionPatch.m

#import "AVAudioSessionPatch.h"

@implementation AVAudioSessionPatch

+ (BOOL)setSession:(AVAudioSession *)session category:(AVAudioSessionCategory)category withOptions:(AVAudioSessionCategoryOptions)options error:(__autoreleasing NSError **)outError {
    return [session setCategory:category withOptions:options error:outError];
}

@end

Then add that to your bridging header:

// xxx-Bridging-Header.h

#import "AVAudioSessionPatch.h"

Then you can call it from Swift like so:

// xxx.swift

try AVAudioSessionPatch.setSession(session, category: .playAndRecord, with: [.defaultToSpeaker, .duckOthers])

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

4 Likes

See also:

1 Like

Thank you!

Thanks for the reference, I really need to grasp the basics of linking objective-C with swift

OpenRadar: rdar://45397675: AVAudioSession.setCategory(_:) is incorrectly unavailable in Swift 4.2 for iOS 9 and older

I found more better solution here. It just calls the setCategory method using NSObject's perform(_:with:).

Thank you so much, this is exactly what I needed to migrate our project to Swift 4.2 because we still support iOS 9. And of course, it was @eskimo . That guy is everywhere (here, Apple Forum, SO, ... and probably the River Styx). I am beginning to think there are multiples of him, like the Dread Pirate Roberts. ;)

2 Likes

It seems that with Xcode 10.2 this has been fixed.