Pass by reference and objc_unretainedPointer from iOS5
I'm attempting to use the SFHF keychain classes (from here) with an IOS 5 project. I've successfully converted most of the class over to abide by the new ARC rules.
I'm having some trouble with one small section of the code as follows
OSStatus status = SecItemCopyMatching((CFDictionaryRef) objc_unretainedPointer(attributeQuery), (CFTypeRef *) objc_unretainedPointer(&attributeResult)
This gives the following syntax issue:
warning: Semantic Issue: Inc开发者_运维技巧ompatible pointer types passing 'NSDictionary *__strong *' to parameter of type 'id'
I'm rather new to iOS development and this has me pretty much stumped right now. Any help is greatly appreciated.
This is the declaration of the API:
OSStatus SecItemCopyMatching (
CFDictionaryRef query,
CFTypeRef *result
);
The result
is a pass-by-reference return value.
Declare a local variable of type CFTypeRef
, call the function and pass the address of said local as per the API, then do any ARC specific shenanigans after the function call.
Yes -- the error is correct. You aren't passing a CFTypeRef, you are passing a CFTypeRef* and objc_unretainedPointer() has no clue what to do with that.
Do something like:
CFTypeRef localResult
SecItemCopyMatching(query, &localResult);
if (... no error ...) {
result = objc_retainedObject(localResult);
}
Had trouble with this call, this is the code I got to work:
NSMutableDictionary *queryDictionary = [[NSMutableDictionary alloc] init];
// Set some properties.
[queryDictionary setObject:[key dataUsingEncoding:NSUTF8StringEncoding] forKey:(__bridge id)kSecAttrGeneric];
[queryDictionary setObject:(id) kCFBooleanTrue forKey:(__bridge id)kSecReturnAttributes];
[queryDictionary setObject:(__bridge id) kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
[queryDictionary setObject:(id) kCFBooleanTrue forKey:(__bridge id)kSecReturnData];
[queryDictionary setObject:(__bridge id) kSecClassGenericPassword forKey:(__bridge id)kSecClass];
CFTypeRef attributes;
OSStatus keychainError = SecItemCopyMatching((__bridge CFDictionaryRef)(queryDictionary), &attributes);
if (keychainError == errSecSuccess)
{
NSDictionary *returnedDictionary = (__bridge_transfer NSDictionary *)attributes;
NSData *rawData = [returnedDictionary objectForKey:(__bridge id)kSecValueData];
return [[NSString alloc] initWithBytes:[rawData bytes] length:[rawData length] encoding:NSUTF8StringEncoding];
}
精彩评论