2011-10-19 5 views
9

그래서 이전 프로젝트를 자동 참조 계산으로 변환하려고합니다. xCode 변환 도구를 사용하려고하지만 변환 할 수 전에 몇 가지 문제를 해결하려면 말한다. 이 오류를 수정하는 방법을 모르겠습니다. 키 체인 파일 구현에 있습니다. 이 메서드는 오류, 특히 SecItemCopyMatching이있는 줄을 반환하는 메서드입니다. "CFTypeRef * '(일명'const void ** ')에 대한 Objective-C 포인터에 대한 간접 포인터의 캐스트가 ARC와 함께 허용되지 않습니다. Google, Apple docs, 및 기타 쓰레기의 무리와 키 체인에서 기존 데이터 사전을 가져 오기 위해 더 나은 방법을 찾을 수 없습니다가. 어떤 도움에 감사드립니다. 감사합니다!iPhone에서 키 체인에서 데이터 사전 가져 오기

-(NSMutableDictionary*)fetchDictionary { 

NSMutableDictionary *genericPasswordQuery = [self buildSearchQuery]; 

NSMutableDictionary *outDictionary = nil; 
OSStatus status = SecItemCopyMatching((__bridge_retained CFDictionaryRef)genericPasswordQuery, (CFTypeRef*)&outDictionary); 

if (DEBUG) printf("FETCH: %s\n", [[self fetchStatus:status] UTF8String]); 

if (status == errSecItemNotFound) return NULL; 
return outDictionary; 

}

답변

41

당신은 ARC를 비활성화 할 필요가 없습니다 이를 위해 검색어 결과를 CFDictionaryRef으로 신고 한 다음 전화를 걸어 NSDictionary으로 전송하면됩니다.

/*1*/ CFDictionaryRef cfquery = (__bridge_retained CFDictionaryRef)genericPasswordQuery; 
/*2*/ CFDictionaryRef cfresult = NULL; 
/*3*/ OSStatus status = SecItemCopyMatching(cfquery, (CFTypeRef *)&cfresult); 
/*4*/ CFRelease(cfquery); 
/*5*/ NSDictionary *result = (__bridge_transfer NSDictionary *)cfresult; 
발언의

커플 : 1 호선에서

  • , 우리는 핵심 재단 국가에 코코아 땅에서 쿼리를 변환합니다. __bridge_retained을 사용하여 ARC가 작업하는 동안 ARC가 개체를 해제하고 할당을 해제하지 않도록합니다. 이러한 종류의 브리징 캐스트는 물체를 보유하므로 누출을 막기 위해 어딘가에 해당 CFRelease을 붙여야합니다. SecItemCopyMatching은 확실히 우리를 위해 쿼리를 공개하지 않을 것입니다. 그래서 우리가 유지 된 브릿지를 사용한다면 결과로 나온 핵심 파운데이션 객체를 릴리즈 할 필요가 있습니다. (우리가 4 행에서 수행)
  • 라인 2, 3 및 4는 코어 파운데이션 유형을 사용하는 순수한 C 코드이므로 ARC는 아무 것도하지 않거나 그에 대해 불평하지 않습니다.
  • 5 번 줄에서 우리는 SecItemCopyMatching이 보유 수를 1로하여 그 결과를 생성했음을 ARC에 알려주며, 우리는이를 릴리스해야 할 책임이 있습니다. (이름에 "복사"가 있기 때문에 이것을 알고 있습니다.) __bridge_transfer은 ARC에이 책임에 대해 알려주므로 자동으로 처리 할 수 ​​있습니다.
  • SecItemCopyMatching에서 반환 된 변경 불가능한 Core Foundation 사전을 NSMutableDictionary으로 변환하지 마십시오. 그건 틀 렸습니다. 또한 일반적인 코코아 스타일 규칙 인 buildSearchQueryNSMutableDictionary을 반환합니다. Simple NSDictionary 두 경우 모두 제대로 작동합니다.

여기 엄지 손가락의 규칙은 "복사"또는 "만들기"함수의 결과는 코코아 땅 __bridge_transfer을 사용하여에 던져해야합니다 동안 __bridge_retained 요구하는 CFRelease가 반드시 따라야 할 것입니다.

+0

조언을 내게 뭔가 같은 질문에 관한 여기에 http://stackoverflow.com/questions/16780202/secitemcopymatching-still-leak-on-osx-under-arc – user170317

0

방법 2 : 한 번 사용하면 왜 유지 또는 전송해야합니까? 테스트는, (memleaks)를 debuging 나를 위해 눈에 바닥 직장에서 예를 모두 통과 : 오직 한 가지가 누출에게 출시되지 않은 autoretained 변수를 한 키()

발견 될 때
CFDictionaryRef keyAttributes = NULL; /* variable for store attributes */ 

NSMutableDictionary *credQuery = [NSMutableDictionary dictionary]; // credential Query 

/* Here you add some options for search your key */ 

OSStatus errGather = SecItemCopyMatching(
    (__bridge CFDictionaryRef)credQuery, 
    (CFTypeRef *)&keyAttributes 
); 

if (errGather == errSecSuccess) { 
    // Gather stored key 
    NSDictionary *keychainDict = (__bridge NSDictionary *)keyAttributes; 
    NSData *passData = keychainDict[(__bridge id<NSCopying>)kSecValueData]; // password 
    ... 
    /* work with gathered data :) */ 
    ... 
    CFRelease(keyAttributes); // (1) HERE. Release when CFType is retained really :) 
    credQuery = nil; 
    keychainDict = nil; 
    passData = nil; 
} 
2

방법 3 : ARC는하자 무거운 (또는 방법 1 및 2에있어서의 조합)

NSMutableDictionary* query = [NSMutableDictionary dictionaryWithDictionary: 
@{ 
    (__bridge id) kSecClass : (__bridge id) kSecClassGenericPassword, 
    (__bridge id) kSecAttrService : nssService, 
#if ! TARGET_IPHONE_SIMULATOR 
    (__bridge id) kSecAttrAccessGroup : @"PRODUCT.com.COMPANY.GenericKeychainSuite", 
#endif 

    (__bridge id) kSecMatchLimit : (__bridge id) kSecMatchLimitOne, 
    (__bridge id) kSecReturnAttributes : (__bridge id) kCFBooleanTrue, 
}]; 

if ([nssAccount length] != 0) 
    [query setObject:nssAccount forKey:(__bridge id) kSecAttrAccount]; 

CFDictionaryRef cfresult; 
auto err = ::SecItemCopyMatching((__bridge CFDictionaryRef)query, 
            (CFTypeRef*)&cfresult); 
if (err == errSecItemNotFound) 
    return std::wstring(); 
else if (err != noErr) 
    throw std::exception(); 

NSDictionary* result = (__bridge_transfer NSDictionary*) cfresult; 

SecItemCopyMatching 들어오는 사전을 소유 할 필요가 없으므로 __bridge 적절한 한 후 ARC 쿼리의 수명을 관리하는 것을 계속한다.

결과의 소유권을 아크로 이전하면 의 결과도 관리 할 수 ​​있으며 모든 코드에 대해 경로에 CFRelease를 기억해야합니다.