5. __strong keyword
• 객체 데이터 형의 기본값.
{
// #1 (암묵적으로 속성 설정)
id obj = [[NSObject alloc] init];
}
{
// #2 (명시적으로 속성 설정)
id __strong obj = [[NSObject alloc] init];
}
5
6. __strong keyword
• 생명주기 - 지역변수 case
- (void)test
{
{
// 객체를 생성하고 소유권을 갖는다.
id __strong obj = [[NSObject alloc] init];
}
// obj 변수가 scope를 벗어나면 강한 참조는 사라짐.
// 객체는 자동으로 릴리스되고, 아무도 객체에 대한 소유권이 없기 때문에 객체는 사라짐.
}
6
8. __strong keyword
• Practice
id __strong obj0 = [[NSObject alloc] init];
id __strong obj1 = [[NSObject alloc] init];
id __strong obj2 = nil;
obj0 = obj1;
obj2 = obj0;
obj1 = nil;
obj0 = nil;
obj2 = nil;
8
9. __weak keyword
• 순환참조를 방지하기 위한 keyword
• 객체를 소유하지 않음
• 순환참조 : 서로다른 객체가 서로의
소유권을 갖고 있는 상태로서, 객체가
제거되어야 할 시점에 제거 되지 않고
메모리에 존재하는 현상
9
10. __weak keyword
{
// Bad case
// warning: Assigning retained object to weak variable;
// object will be released after assignment
id __weak obj = [[NSObject alloc] init];
}
{
// Good case
id __strong obj0 = [[NSObject alloc] init];
id __weak obj1 = obj0;
}
10
12. __unsafe_unretained keyword
• 해당 키워드로 설정한 변수는 컴파일러의 ARC 정책에서
제외된다. 때문에, 직접변수를 관리해 주어야 한다.
• __weak 와 마찬가지로 객체의 소유권을 갖지 않는다.
• __weak 와 다른 점은 객체 소멸 후 nil 설정이 되지 않는
다.
12
13. __autoreleasing keyword
• @autoreleasepool 블록에 따른 생명 주기를 갖도록 한
다.
@autoreleasepool {
// @autoreleasepool block이 사라질 때 함께 소멸됨.
id __autoreleasing obj = [[NSObject alloc] init];
}
13
14. __autoreleasing keyword
• 메소드 명명 규칙을 지켜야 한다. (컴파일러가 메소드의
이름에 따라 __autoreleasing을 처리하기 때문)
• 객체를 생성하지 않고 얻어오려면 alloc/new/copy/
mutableCopy 메소드 그룹이 아닌 다른 메소드를 사용해
야 하는데, init 계열 메소드를 제외한 다른 메소드에서 반
환한 객체는 컴파일러가 자동으로 @autoreleasepool
block에 등록 시킨다.
14
15. __autoreleasing keyword
@autoreleasepool {
/*
* 1. 변수 obj는 __strong 키워드에 따라 객체 소유권 가짐. (+1)
* 2. +[NSMutableArray array] 메소드의 이름을 보고 컴파일러가
* @autoreleasepool block 에 등록. (+2)
*/
id __strong obj = [NSMutableArray array];
}
/*
* 변수 obj는 scope를 벗어나 소유권 해체됨. (객체 릴리즈됨) (+1)
* @autoreleasepool block이 사라지면서 등록된 모든 객체 릴리즈. (0)
*/
15
16. __autoreleasing keyword
• id or 객체 데이터형의 포인터는 기본으로 __autoreleasing 속
성을 갖는다.
{
// 컴파일 오류
NSError *error = nil;
// NSError * __strong error = nil; (변경된 코드)
NSError **pError = &error;
// NSError * __autoreleasing *pError = &error; (변경된 코드)
}
{
// 정상 컴파일
NSError *error = nil;
// NSError * __strong error = nil; (변경된 코드)
NSError * __strong *pError = &error;
}
16
17. 규칙
• retain, release, retainCount, autorelease는 잊어라.
• NSAllocateObject and NSDeallocateObject는 잊어라.
• 객체 생성에 관련된 메서드 작명 규칙을 따라라.
• dealloc 을 잊어라.
• NSAutoreleasePool 대신 @autoreleasepool을 사용하라.
• Zone(NSZone)을 잊어라.
• 객체 타입의 변수들은 C 언어의 구조체 or 공용체의 멤버가 될 수 없다.
• ‘id’ and ‘void *’ 는 명시적으로 형 변환되어야 한다.
17
18. 규칙
“객체 생성에 관련된 메서드 작명 규칙을 따라라.”
• alloc
• new
• copy
• mutableCopy
• 위 목록 중의 하나로 시작되는 method에서 객체가 반환되었을
때 method를 호출한 객체는 소유권을 갖게 된다. (non-arc, arc
모두 해당하는 내용)
18
19. 규칙
“객체 생성에 관련된 메서드 작명 규칙을 따라라.”
• init
• 이 method는 인스턴스 method여야 한다.
• 이 method는 객체를 반환해야 한다.
• 반환 타입은 ‘id’ 타입이어야 한다. 또는 해당 클래스, 슈퍼 클래스,
서브 클래스의 객체이어야 한다.
// good
- (id)initWithObject:(id)obj;
// bad
+ (id)initWithObject:(id)obj;
// bad
- (void)initThisObject;
// usable
- (void)initialize;
19
21. 규칙
“객체 타입의 변수들은 C 언어의 구조체 or 공용체의 멤버가 될 수 없다.”
• C 구조체는 멤버들의 정보가 없기 때문에 컴파일러가 C 구조체
의 메모리를 관리하는 것은 불가능하다.
// 컴파일 에러
struct Data {
NSString *name;
};
// 컴파일 정상
struct Data {
NSString * __unsafe_unretained name;
};
21
22. 규칙
‘id’ and ‘void *’ 는 명시적으로 형 변환되어야 한다.
• __bridge cast
• 단순 할당할 때 사용
- (void)test
{
id obj = [[NSObject alloc] init];
{
// 컴파일 오류
void *ptr = obj;
}
{
// 컴파일 정상
void *ptr = (__bridge void *)obj;
}
}
22
23. 규칙
‘id’ and ‘void *’ 는 명시적으로 형 변환되어야 한다.
• __bridge_retained cast
• 할당한 변수가 객체의 소유권을 가진 것으로 동작한다.
{
// ARC
NSArray *array = [[NSArray alloc] init];
CFArrayRef arrayRef = (__bridge_retained CFArrayRef)array;
}
{
// non-ARC
NSArray *array = [[NSArray alloc] init];
CFArrayRef arrayRef = (CFArrayRef)[array retain];
}
23
24. 규칙
‘id’ and ‘void *’ 는 명시적으로 형 변환되어야 한다.
• __bridge_transfer cast
• 할당이 된 직후에 객체를 릴리즈 한다.
{
// ARC
void *p = (__bridge_retained void *)[[NSObject alloc] init];
NSLog(@"class = %@", [(__bridge id)p class]);
(void)(__bridge_transfer id)p;
}
{
// non-ARC
void *p = (void *)[[NSObject alloc] init];
NSLog(@"class = %@", [(id)p class]);
[(id)p release];
}
24
25. 규칙
‘id’ and ‘void *’ 는 명시적으로 형 변환되어야 한다.
NS_INLINE CF_RETURNS_RETAINED CFTypeRef CFBridgingRetain(id X) {
return (__bridge_retained CFTypeRef)X;
}
NS_INLINE id CFBridgingRelease(CFTypeRef CF_CONSUMED X) {
return (__bridge_transfer id)X;
}
25
26. 참고
• iOS와 OS X의 메모리 관리와 멀티스레딩 기법 (지앤선) -
가즈키 사카모토, 도모히코 후루모토(지음), OSXDEV(옮
김)
26