본 게시물은 Saurav Satpathy님의 게시글 Attributes of @property : nonatomic, retain, strong, weak etc..을 바탕으로 작성되었습니다.
@property의 특성: nonatomic, retain, strong, weak 등
본 게시글은 프로퍼티 특성(property attribute)에 대한 참고 자료로서 작성되었습니다.
기본적으로 @property
는 다음과 같이 생겼습니다.
@property (atomic, readonly, strong) NSString * name;
또는 다음과 같이 생겼습니다.
@property (atomic, readwrite, assign) NSInteger age;
1. 접근 특성(access attributes)
(1-1) readonly
name
의 선언에서 보이는 바와 같이 그 프로퍼티로 어떤 값이 대입(assign)될 수 없습니다. readonly
특성이 적용된 프로퍼티 내부에는 세터(setter) 메소드가 생략되기 때문입니다.
(1-2) readwrite
그 프로퍼티가 갖는 값을 다른 곳으로 가져갈 수 있을 뿐만 아니라, 프로퍼티가 갖는 값이 다른 값으로 대체될 수도 있습니다.
2. 쓰레드 특성(threading attributes)
(2-1) atomic
어떤 프로퍼티를 atomic
으로 선언하는 것은, 컴파일러로 하여금 그 객체에 대해 여러 쓰레드(thread)에서 동시 접근하는 것을 방지하는 부가적은 코드를 생성하도록 지시합니다.
이 부가적인 코드에서는 세마포어(semaphore)를 잠그고(lock), 그 프로퍼티에 대해 값을 가져오거나 설정한 다음, 다시 세마포어의 잠금을 해제(unlock)합니다. 세마포어를 잠그거나 잠금 해제하는 것은 비용이 들지만(물론 보통은 이 정도의 비용은 경미한 편이지만), 그 프로퍼티의 값을 가져오거나 설정하는 과정이 온전하게 수행됨을 보장합니다.
(2-2) nonatomic
프로퍼티 내부의 접근 메소드가 그 값을 단순히 반환하거나 수정하도록 지시합니다. 서로 다른 쓰레드로부터 동시에 이 값에 접근해 올 경우 어떤 일이 벌어질 지에 대해서는 보장이 되지 않습니다. 이런 이유로 인해 atomic
으로 선언된 프로퍼티보다 nonatomic
으로 선언되는 프로퍼티가 (안전성은 낮지만) 접근 속도가 빠릅니다.
3. 메모리 관리 특성(memory management attributes) 및 수명 한정자(lifetime qualifiers)
많은 언어들은 가비지 콜렉터(garbage collector)를 통해 메모리 관리 기능을 지원하지만, Objective-C에서는 객체 소유(object ownership)나 레퍼런스 카운트(reference counting)이라고 불리는 보다 효율적인 대체 수단을 사용합니다.
(3-1) strong과 retain
어떤 프로퍼티를 strong
으로 선언한다는 것은 그 프로퍼티가 참조하고자 하는 객체를 “소유(own)”한다는 뜻입니다. 이렇게 선언된 프로퍼티에 여러분이 어떤 데이터를 대입시키면, 그 프로퍼티가 strong
참조로써 다른 데이터를 참조하게 되지 않는 한, 그 데이터는 파괴되지 않을 것입니다.
Objective-C에서 한 객체는 다른 객체들로부터 적어도 한 번은 참조되고 있다면 그 객체는 계속하여 유효한 상태로 남아 있습니다.
non-ARC 코드에서 strong
은 단지 retain
과 같은 말일 뿐입니다.
어떤 변수가 있을 때 그 변수가 스코프(scope)에서 유효할 동안 또는 그 변수가 다른 객체나 nil
을 참조할 때까지 그 변수는 가리키고 있는 객체와 strong
참조를 유지하고 있습니다.
// Example
@property (nonatomic, strong) NSArray * listOfStudents;
(3-2) weak
weak
은 “누군가가 그 객체를 strong
참조를 하는 한 그 객체를 메모리에 남아있게 하라”는 의미를 갖고 있으며 여러분이 그 객체의 수명에 관여하지 않을 때 지정합니다. 여러분이 weak
참조로 어떤 객체를 참조하면, 그 객체는 다른 객체에 의해 strong
참조되고 있는 한 weak
참조하고 있는 이 쪽에서도 계속 유효하지만, 어떤 객체도 참조하지 않게 될 때 weak
참조로 참조하던 객체는 파괴(destroy)됩니다.
델리게이트 형식의 프로퍼티(delegate property)는 순환적으로 retain
되는 것을 방지하기 위해 weak
참조가 됩니다.
IBOutlet
이나 서브 뷰(Subview)는 슈퍼 뷰(Superview)에 의해 strong
참조되고 있기 때문에 다른 코드에서는 weak
참조가 됩니다.
// Example
@property (nonatomic, weak) id<SampleDelegate> sDelegate;
@property (nonatomic, weak) IBOutlet UILabel * titleLabel;
(3-3) assign
새 값으로서 프로퍼티에 대입됩니다. 이 특성은 대개 int
, float
, NSInteger
등의 프리미티브 타입(primitive type)의 프로퍼티에 적용됩니다.
(3-4) copy
객체가 수정 가능(mutable)할 때 이 특성이 적용됩니다. 프로퍼티에 참조될 객체가 지금 이 순간의 상태로 참조되길 원하며 이후에 다른 요소에 의해 변경되는 것을 여기에서 반영하고 싶지 않을 때 이 특성을 사용하면 됩니다. 다만 이 프로퍼티에 참조되는 객체는 원본에 대한 복사본으로서 현재의 프로퍼티에 의해 retain
된 상태이기 때문에, 사용이 끝났다면 여러분이 직접 해제(release)해야 합니다.
이 특성이 적용된 프로퍼티로 객체가 참조될 때 원본과는 다른 메모리 위치에 복사가 이뤄지며 그 복사본의 참조 횟수(retain count)가 증가된 후 해당 프로퍼티에 참조됩니다. 이 참조 횟수는 여러분이 그 객체를 더 이상 소유하고 있지 않을 때 자동으로 감소되겠으나, non-ARC 환경이라면 여러분이 직접 명시적으로 해제해 주어야 합니다.
참고 여러분이 mutable 프로퍼티에 대해 copy
특성을 사용하여 선언하였다면, 여러분이 이를 mutable이라 선언했어도 여전히 immutable입니다. 여러분이 여기에 어떤 값이나 객체를 가감하려 한다면 예외가 throw
될 것입니다.
(3-5) unsafe_unretained
이 특성은 Cocoa 및 Cocoa Touch의 클래스 중 weak
참조를 지원하지 않는 극히 일부 클래스에 대해 사용됩니다. 여러분이 그러한 클래스 형식의 객체에 대해 정보를 얻고자 할 때 weak
참조의 로컬 변수나 weak
참조의 프로퍼티를 사용할 수 없음을 의미합니다. 이 특성은 참조된 객체를 계속해서 유효한 상태로 유지하는 능력이 없으면서 그 객체에 대한 strong
참조가 없어져도 이 특성을 갖는 프로퍼티는 nil
참조로 바뀌지 않는다는 뜻입니다. 때문에 이 특성을 가진 프로퍼티가 가리키는 객체가 할당 해제(deallocated)되었다면, 이 프로퍼티가 갖는 포인터는 오류입니다.
4. getter=
직접 작성한 메소드를 프로퍼티에 대한 getter
로서 사용할 때 이 특성을 적용합니다.
5. setter=
직접 작성한 메소드를 프로퍼티에 대한 setter
로서 사용할 때 이 특성을 적용합니다.