简体   繁体   中英

Crash while trying to get UIDevice.current.identifierForVendor?.uuidString

I have crash while trying to do:

static func getDeviceUUID() -> String {
        guard let uuid = UIDevice.current.identifierForVendor?.uuidString else {
            assertionFailure("Nil while unwrapping UIDevice.current.identifierForVendor?.uuidString")
            return ""}
            return uuid
    }

Error says: Thread 9: Fatal error: Nil while unwrapping UIDevice.current.identifierForVendor?.uuidString

But when i try to log it out in console it says:

 po UIDevice.current.identifierForVendor?.uuidString
▿ Optional<String>
  - some : "39DEFA50-D6A1-4788-BCCC-5E2A28A04C57"

So, it actually have value. Why crash is happening?

It's working fine

func getDeviceUUID() -> String {
        guard let uuid = UIDevice.current.identifierForVendor?.uuidString else {
            assertionFailure("Nil while unwrapping UIDevice.current.identifierForVendor?.uuidString")
            return ""}
        return uuid
    }

print(getDeviceUUID()) //50E6548C-0BB4-4979-8F5F-DFAD422BEB26

I've had a similar problem occur when trying to grab the IDFA from the AdSupport framework:

ASIdentifierManager.shared().advertisingIdentifier.uuidString
// causes exception

In this case, it seems as though the Objective-C code base has an incorrectly marked 'nonnull' method, which can't be worked around because the uuidString method for the UUID class returns a value type (String), whereas in Obj-C it would return a reference type (NSString): https://forums.swift.org/t/is-it-safe-to-cast-a-nonnull-objc-type-to-a-swift-optional/10658

Since these both make use of the UUID class, my guess is that it's the same problem.

The workaround that the above link suggests is to build an Obj-C wrapper for accessing the UUID:

+ (nullable NSString*)getUUIDFromDevice {
    NSString *uuid = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
    if (uuid) {
        return uuid;
    } else {
        return nil;
    }
}

Unfortunately this is difficult to test, because it's unclear when exactly the UUID value would ever be nil.

Maybe because you didn't check if user permit ti check it.

guard ASIdentifierManager.shared().isAdvertisingTrackingEnabled else {
    return nil
}          
return ASIdentifierManager.shared().advertisingIdentifier.uuidString

BTW, for iOS14+ you should check it differently:

import AdSupport
import AppTrackingTransparency

extension ASIdentifierManager {
    //NOTE: if the user has enabled Limit Ad Tracking, this IDFA will be all zeros on a physical device
    static var identifierForAdvertising: String {
        if #available(iOS 14, *) {
            guard ATTrackingManager.trackingAuthorizationStatus == .authorized else {
                return ""
            }
        } else {
            guard ASIdentifierManager.shared().isAdvertisingTrackingEnabled else {
                return ""
            }
        }
        return ASIdentifierManager.shared().advertisingIdentifier.uuidString
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM