Paul
Paul

Reputation: 1019

Comparing Unmanaged<AnyObject> to nil

The code is copied from this blog post: http://matthewpalmer.net/blog/2014/06/21/example-ios-keychain-swift-save-query/

I used to have this code:

// Search for the keychain items
let status: OSStatus = SecItemCopyMatching(keychainQuery, &dataTypeRef)

// The following line crashes with an EXEC_BAD_ACCESS if dataTypeRef is nil
var opaque = dataTypeRef!.toOpaque()

When I run the above using a new account value in the keychain query the dataTypeRef will be nil which leads to an EXEC_BAD_ACCESS.

I tried to circumvent this by checking if dataTypeRef is nil like this:

var opaque = COpaquePointer.null()
if (dataTypeRef != nil) {
    opaque = dataTypeRef!.toOpaque()    // This line should not be executed.
}

While the debugger shows that dataTypeRef is nil it will still enter the if clause and crash.

Could anyone explain what is going on here? I do have experience in Objective-C but I can't figure out what's going on here.

Upvotes: 3

Views: 1377

Answers (1)

Martin R
Martin R

Reputation: 539685

As far as I know, the toOpaque/fromOpaque dances are no longer necessary, and you can simply use optional binding. This can be combined with the cast to NSData using optional chaining:

let status: OSStatus = SecItemCopyMatching(keychainQuery, &dataTypeRef)
if let retrievedData = dataTypeRef?.takeRetainedValue() as? NSData {
    contentsOfKeychain = NSString(data: retrievedData, encoding: NSUTF8StringEncoding)
}

Note also that takeRetainedValue() is the correct choice here because you "own" the item returned by SecItemCopyMatching (it has "Copy" in its name).

But actually you should check the return value first:

let status: OSStatus = SecItemCopyMatching(keychainQuery, &dataTypeRef)
if status == errSecSuccess {
    if let retrievedData = dataTypeRef?.takeRetainedValue() as? NSData {
        contentsOfKeychain = NSString(data: retrievedData, encoding: NSUTF8StringEncoding)
    }
}

Upvotes: 6

Related Questions