어떤 상황에서 ARC에서 __autoreleasing 소유권 한정자를 작성해야합니까?


118

퍼즐을 풀려고합니다.

__strongNSObject, NSString 등과 같은 모든 Objective-C 유지 가능 개체 포인터의 기본값입니다. 강력한 참조입니다. ARC -release는 범위의 끝에서 균형을 유지합니다 .

__unsafe_unretained옛날 방식과 같습니다. 유지 가능한 개체를 유지하지 않고 약한 포인터에 사용됩니다.

__weak__unsafe_unretained참조 된 객체가 할당 해제 되 자마자 포인터가 nil로 설정된다는 것을 의미하는 자동 영점 약한 참조라는 점을 제외하면 비슷 합니다. 이것은 댕글 링 포인터와 EXC_BAD_ACCESS 오류의 위험을 제거합니다.

그러나 정확히 무엇이 __autoreleasing좋은가요? 이 한정자를 사용해야 할 때에 대한 실용적인 예를 찾는 데 어려움을 겪고 있습니다. 나는 다음과 같은 포인터 포인터를 기대하는 함수와 메서드에만 해당한다고 생각합니다.

- (BOOL)save:(NSError**);

또는

NSError *error = nil;
[database save:&error];

ARC에서 다음과 같이 선언해야합니다.

- (BOOL)save:(NSError* __autoreleasing *);

그러나 이것은 너무 모호하며 이유 를 완전히 이해하고 싶습니다 . 내가 찾은 코드 스 니펫은 두 별 사이에 __autoreleasing을 배치하는데 이상하게 보입니다. 유형은 NSError**(NSError에 대한 포인터 포인터)이므로 왜 __autoreleasing별 사이에 배치 하고 단순히 NSError**?

또한 내가 의존해야하는 다른 상황이있을 수 있습니다 __autoreleasing.


1
나는이 같은 질문을 가지고 있으며 아래 답변은 완전히 설득력이 없습니다 ... 예를 들어, 시스템이 당신과 같은 __autoreleasing 데코레이터로 선언 된 NSError ** 인수를 사용하는 인터페이스를 제공하지 않는 이유와 Transitioning to Arc Release Notes에서 다음과 같이 말합니다. 해야한다? 예를 들어, NSFileManager.h에있는 이러한 많은 루틴 중 하나는?
Dad

답변:


67

네가 옳아. 공식 문서에서 설명하는대로 :

__autoreleasing은 참조 (id *)로 전달되고 반환시 자동 해제되는 인수를 나타냅니다.

이 모든 것은 ARC 전환 가이드 에 잘 설명되어 있습니다.

NSError 예제에서 선언은 __strong암시 적으로 다음을 의미합니다 .

NSError * e = nil;

다음으로 변환됩니다.

NSError * __strong error = nil;

save메서드 를 호출 할 때 :

- ( BOOL )save: ( NSError * __autoreleasing * );

그런 다음 컴파일러는에 설정된 임시 변수를 만들어야합니다 __autoreleasing. 그래서:

NSError * error = nil;
[ database save: &error ];

다음으로 변환됩니다.

NSError * __strong error = nil;
NSError * __autoreleasing tmpError = error;
[ database save: &tmpError ];
error = tmpError;

오류 객체를로 __autoreleasing직접 선언하여이를 방지 할 수 있습니다.


3
아니요, __autoreleasing참조로 전달 된 인수에만 사용됩니다. 개체의 포인터에 대한 포인터가 있으므로 이것은 특별한 경우입니다. 편의 생성자와 같은 것은 객체에 대한 포인터 만 반환하고 ARC가 자동으로 처리하기 때문에 그렇지 않습니다.
Macmade

7
__autoreleasing 한정자가 NSError ** 앞이 아닌 별 사이에 배치되는 이유는 무엇입니까? 유형이 NSError **이므로 이상하게 보입니다. 아니면 이것이 가리키는 NSError * 포인터가 자동 해제 된 객체를 가리키는 것으로 규정되어야한다는 것을 나타내려고하기 때문입니까?
Proud Member

1
귀하의 첫 번째 의견과 관련하여 @Proud Member-정확하지 않습니다 (정확하게 이해하는 경우)-아래 Glen Low의 답변을 참조하십시오. 오류 개체가 생성되고 저장 함수 에서 자동 해제 변수 (전달한 변수)에 할당됩니다 . 이 할당으로 인해 해당 시점에 개체가 유지되고 자동 해제됩니다. save 함수의 선언은 자동 해제 변수가 아닌 다른 것을 보내지 못하게합니다. 이것이 필요한 이유입니다. 이것이 우리가 시도하면 컴파일러가 임시 변수를 생성하는 이유입니다.
Colin

2
그렇다면 왜 Apple 인터페이스에 이러한 기능이없는 것 같습니까? 예를 들어, NSFileManager.h의 모든 것?
Dad

1
@Macmade : 우연히 귀하의 답변이 ( stackoverflow.com/users/12652/comptrol의해 ) 수정되었음을 알아 차렸고 최소한 귀하의 첫 번째 예에 대한 변경 사항 ( "암시 적으로 ... ...) 왜냐하면 __strong 한정자가 두 번째 줄에서 첫 번째 줄로 옮겨 졌기 때문입니다. 아마도 당신은 그것을 확인할 수있을 것입니다.
Martin R

34

Macmade의 답변과 Proud Member의 댓글에 대한 후속 질문에 대한 후속 조치 (댓글로 게시했을 수도 있지만 최대 문자 수를 초과 함) :

다음은 __autoreleasing의 변수 한정자가 두 별 사이에 배치 된 이유입니다.

서문에 한정자를 사용하여 개체 포인터를 선언하는 올바른 구문은 다음과 같습니다.

NSError * __qualifier someError;

컴파일러는 이것을 용서할 것입니다 :

__qualifier NSError *someError;

그러나 그것은 정확하지 않습니다. Apple ARC 전환 가이드를 참조하십시오 ( "변수를 올바르게 장식해야합니다 ..."로 시작하는 섹션 참조).

당면한 질문에 답하기 위해 : 메모리 주소를 가리키는 포인터는 객체에 대한 포인터가 아니라 기본 유형에 대한 포인터이기 때문에 이중 포인터는 ARC 메모리 관리 한정자를 가질 수 없습니다. 그러나 이중 포인터를 선언 할 때 ARC는 두 번째 포인터에 대한 메모리 관리 규칙이 무엇인지 알고 싶어합니다. 이것이 이중 포인터 변수가 다음과 같이 지정되는 이유입니다.

SomeClass * __qualifier *someVariable;

따라서 이중 NSError 포인터 인 메서드 인수의 경우 데이터 유형은 다음과 같이 선언됩니다.

- (BOOL)save:(NSError* __autoreleasing *)errorPointer;

영어로 "__autoreleasing NSError 객체 포인터에 대한 포인터"라고 말합니다.


15

최종 ARC 사양은 말한다

__autoreleasing 객체의 경우 새 포인터가 유지되고 자동 해제되며 기본 의미 체계를 사용하여 lvalue에 저장됩니다.

예를 들어, 코드

NSError* __autoreleasing error = someError;

실제로 변환됩니다

NSError* error = [[someError retain] autorelease];

... 이것이 매개 변수가있을 때 작동하는 이유입니다 NSError* __autoreleasing * errorPointer. 호출 된 메소드는 오류를 할당 *errorPointer하고 위의 의미가 시작됩니다.

__autoreleasing다른 컨텍스트에서 ARC 객체를 자동 해제 풀에 강제로 사용할 수 있지만 ARC는 메서드 반환시 자동 해제 풀을 사용하는 것처럼 보이며 이미 자동으로 처리하기 때문에별로 유용하지 않습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.