Is it safe to cast a nonnull objc type to a Swift optional?

(Whcemyesil) #1


since the advertisingIdentifier of the ASIdentifierManager seems to be incorrectly annotated and therefore causes a crash when accessing the uuidString on Swift (if advertisingIdentifier is nil -
SR-6143), my question is whether it’s safe to do the following for now and future versions of Swift:

guard let advertisingIdentifier = ASIdentifierManager.shared().advertisingIdentifier as UUID? else {
    return "00000000-0000-0000-0000-000000000000"

or is it safer to make an objective c wrapper with a nullable annotation?

(Jordan Rose) #2

You should make the Objective-C wrapper (and sorry on behalf of the AS framework team).

The compiler had a workaround for incorrect nonnulls, but it only works with reference types (i.e. methods where the return type is the same as it is in Objective-C). So you’ll need to use the wrapper function this time.

(Fabian) #3

Thanks Jordan. I have created a Radar, maybe you could push this a little? It’s just a single word after all, and would perfectly fit into the iOS 12 strategy of stability as a main focus.

(Whcemyesil) #4


(Jon Shier) #5

We’ve seen a similar but different problem in Alamofire where the Data passed by the URLSession delegate method is occasionally nil from the Objective-C side but is being bridged as a non-optional and so crashing in the bridge code. Making the delegate method take a Data? works but causes a permanent compiler warning. I imaging dropping to Objective-C could work but causes issues for a potential Linux port. Any better ideas for a workaround or something?

(Ole-Magnus) #6

You know whether this is a valid work-around for getting the uuidString?

let optionalIdfv: UUID! = ASIdentiferManager.shared().advertisingIdentifier
if let idfv = optionalIdfv {
   return idfv.uuidString

(Jordan Rose) #7

I can't remember if that's the syntactic form we treated specially (as opposed to the one whcemyesil posted originally), but that trick is only for reference types. Since UUID is a value type bridged to NSUUID, it won't work, sorry. The workaround has to be on the Objective-C side.

(Ole-Magnus) #8


(Zhihui Tang) #9

If you want to avoid the crash issue, I don't think the code will work.
Actually the crash happens in Object-C side, we can write a OC wrapper to the crash like this:

Create a Header file, and add OCCatch.h in your Bridging-Header.h.

//  OCCatch.h

#ifndef OCCatch_h
#define OCCatch_h

// add the code below to your -Bridging-Header.h

 #import "OCCatch.h"

//   How to use it in Swift?
 let exception = tryBlock {
        let statusBar = UIApplication.shared.value(forKey: "statusBar") as? UIView
  if let exception = exception {  
    print("exception: \(exception)")

#import <Foundation/Foundation.h>

NS_INLINE NSException * _Nullable tryBlock(void(^_Nonnull tryBlock)(void)) {
    @try {
    @catch (NSException *exception) {
        return exception;
    return nil;

#endif /* OCCatch_h */

You can find the file here:

The get the advertisingIdentifier by

let exception = tryBlock {
    let advertisingIdentifier = ASIdentifierManager.shared().advertisingIdentifier
if let exception = exception {
    print("advertisingIdentifier exception: \(exception)")

I haven't tested it, please try and let me know if there is any problem

(Keith Smiley) #10

Another workaround for this specific issue is to use the Objective-C runtime from Swift, which doesn't require any Objective-C code which you may prefer if you have an all Swift codebase

import AdSupport

extension ASIdentifierManager {
    public var safeAdvertisingIdentifier: UUID? {
        return self.perform(#selector(getter: ASIdentifierManager.advertisingIdentifier))?.takeUnretainedValue() as? UUID

(Jordan Rose) #11

Nitpick: that should be as! UUID? rather than as? UUID.