Question

Leak instruments shows number of leaked NSCFData objects and stack trace apparently contains the following method at the end of the boundary of my app methods.

NSData* SAKeychainGetValue(NSString *key)
{
    NSMutableDictionary *searchDictionary = SAGetKeychainSearchDictionary(key);
    [searchDictionary setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
    [searchDictionary setObject:(id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData];

    CFDataRef value = nil;
    OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)searchDictionary, (CFTypeRef *)&value);
    if (status != errSecSuccess && status != errSecItemNotFound)
    {
        NSLog(@"failed to get key %@ with error %ld.", key, (long)status);
    }
    return (__bridge NSData*)value;
}

But I can't see what is wrong with this method to leak.

Was it helpful?

Solution

You should use __bridge_transfer instead of __bridge in (__bridge NSData*)value.

The value return from SecItemCopyMatching method (copy means the value returns should be released in apple naming convention) should be released, so you should transfer the ownership to ARC.

OTHER TIPS

You can try using the static analyser to solve issues like this CMD+Shift+B is the default shortcut

But you're mixing your bridges up

NSData* SAKeychainGetValue(NSString *key)
{
    NSMutableDictionary *searchDictionary = SAGetKeychainSearchDictionary(key);
    [searchDictionary setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
    [searchDictionary setObject:(id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData];

    CFDataRef value = nil;
    OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)searchDictionary, (CFTypeRef *)&value);
    if (status != errSecSuccess && status != errSecItemNotFound)
    {
        NSLog(@"failed to get key %@ with error %ld.", key, (long)status);
    }
    return (__bridge_transfer NSData*)value;
}

You could also probably just use NSData directly:

    NSData *value = nil;
    OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)searchDictionary, (CFTypeRef *)&value);
    ...
    return value;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top