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?
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.
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. Feedback Assistant
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?
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.
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 {
tryBlock();
}
@catch (NSException *exception) {
return exception;
}
return nil;
}
#endif /* OCCatch_h */
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
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
}
}
I'm not at Apple anymore, sorry. But it looks like the headers haven't changed, and if you're still seeing the crash I guess the implementation hasn't changed either. So yes, the workaround is still necessary. :-(