이 글은 아래의 출처를 수정하여 작성한 글 임을 밝힌다.
<출처 : http://wwwww.kr/30792>
NSObject
1. NSObject 클래스
Objective - C 최상위 클래스중의 하나입니다.
CocoaTouch의 모든 클래스는 NSObject 클래스로부터 상속을 받아야 합니다.
이 클래스로부터 상속받지 않으면 인스턴스를 만들 수 가 없습니다.
2. 인스턴스 변수
Class isa
이 변수는 인스턴스가 속한 클래스 객체를 기억하고 있습니다.
직접 사용은 불가능하며 class라는 메서드를 이용해야 합니다.
인스턴스들은 이 변수와 자신의 멤버 변수를 구조체 형태로 메모리 할당을 받습니다.
3. 클래스 객체 관련 메서드
-(Class)class: 클래스 객체를 리턴합니다.
-(id)self: 자기 자신의 id를 리턴합니다.
-(BOOL)isMemberOfClass:(Class)aClass
Class 타입을 매개변수로 받아서 인스턴스가 그 클래스 타입에 속하면 YES를 리턴하고 그렇지 않으면 NO를 리턴합니다.
-(BOOL)isKindOfClass:(Class)aClass
이 메서드는 서브 클래스 여부까지 확인
+(BOOL)isSubclassOfClass:(Class)aClass
그 클래스 자체이거나 서브 클래스이면 YES 아니면 NO를 리턴
-(Class) superclass
슈퍼 클래스 객체 리턴
4. 메모리 생성과 해제
+(id)alloc
메모리 할당을 한 후 retainCount를 1로 초기화하고 id를 리턴합니다. 재정의 하지 않습니다.
-(void)dealloc
retainCount 값에 상관없이 메모리 공간을 해제하는 메서드로 재정의 가능합니다.
-(void)release
retainCount 값을 1감소 - 재정의 하지 않습니다.
-(id)retain
retainCount 값을 1증가 시키고 자신을 리턴
재정의 하지 않습니다.
-(NSUInteger)retainCount
retainCount 값을 리턴 - 재정의하지 않습니다.
-(id)init
초기화 하는 메서드로 재정의 가능. 정해진 패턴으로만 재정의하는 것이 바람직합니다.
+(void)initialize
변수의 초기 설정을 위한 메서드로 직접 호출 불가하며 재정의하지 않습니다.
+(id)new
alloc과 init의 조합으로 재정의하지 않습니다.
-(id)autorelease
현재 유효한 자동 해제 풀에 추가하고 자기 자신의 id를 리턴
메모리 생성과 해제
retainCount : 참조횟수
+ alloc : 메모리 할당 후 retainCount를 1로 만들어 줌(재정의 안함)
- dealloc : retainCount에 상관 없이 메모리 무조건 해제. 일반적으로 재정의 함.
dealloc의 호출방법 : 직접호출이 가능하고 retainCount가 0이되면 자동으로 호출 => 비추
+ (void) dealloc
{
-------------
--------
[super dealloc]; //호출하지 않으면 경고
}
- release : retainCount값을 1 감소시킴 - 재정의 안함.
- retain : retainCount값을 1 증가시키고 자신의 id(주소) 리턴 - 재정의 안함
retainCount : retainCount 리턴 - 재정의 안함
init : 초기화해주는 메서드 - 재정의 함
초기화 방법
01.
- (id) init
02.
{
03.
self:[super init];
04.
if
(slef !=nil)
// self가 nil이 아니라면.
05.
{
06.
할일(초기화);
07.
}
08.
return
self;
09.
}
exit(0); 은 강제로 종료하는 명령어. 모바일뱅킹같은 경우 사용하고 그외엔 거의 사용하지 않는다.
+ (void) initialize : 사용자가 사용할 수 없음. isa같은 걸 초기화 시켜줌. 재정의안함
+ (id)new : alloc -> init, 재정의안함
- (id)autorelease : AutoreleasePool 에 등록해줌. 재정의안함
01.
#import <Foundation/Foundation.h>
02.
int
main (
int
argc,
const
char
* argv[]) {
03.
04.
NSAutoreleasePool *pool = [NSAutoreleasePool
new
];
05.
06.
//obj가 처음 alloc이 되었으므로 메모리 할당을 받고 retainCount는 1
07.
id obj = [[NSObject alloc] init];
08.
NSLog(@
"init: %d"
, [obj retainCount]);
//1
09.
//retain을 호출하면 retainCount가 1 증가
10.
[obj retain];
11.
NSLog(@
"retain: %d"
, [obj retainCount]);
//2
12.
[obj retain];
13.
NSLog(@
"retain: %d"
, [obj retainCount]);
//3
14.
//release 는 retainCount를 1 감소시키고 retainCount 가 0이 되면 dealloc이 호출
15.
[obj release];
16.
NSLog(@
"release: %d"
, [obj retainCount]);
//2
17.
[obj release];
18.
NSLog(@
"release: %d"
, [obj retainCount]);
//1
19.
[pool drain];
20.
return
0;
21.
22.
[pool drain];
23.
return
0;
24.
}
결과
2010-11-09 10:40:18.797 RetainCountTest[943:a0f] init: 1
2010-11-09 10:40:18.799 RetainCountTest[943:a0f] retain: 2
2010-11-09 10:40:18.799 RetainCountTest[943:a0f] retain: 3
2010-11-09 10:40:18.799 RetainCountTest[943:a0f] release: 2
2010-11-09 10:40:18.800 RetainCountTest[943:a0f] release: 1
dealloc
개발자가 dealloc을 직접 호출하는 것은 바람직하지 않습니다.
다른 변수가 참조하고 있는 경우 모르고 해제할 수 있기 때문입니다.
직접 호출하는 것이 에러는 아닙니다.
그리고 복사를 해줄 때도 대입을 이용하는 것은 바람직하지 않습니다.
예제)
01.
#import <Foundation/Foundation.h>
02.
int
main()
03.
{
04.
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc]init];
05.
id obj = [[NSObject alloc] init];
06.
NSLog(@
"init: %d\n"
, [obj retainCount]);
07.
[obj dealloc];
08.
[pool drain];
09.
return
0;
10.
}
자신이 직접 메모리 공간을 해제하는 메서드를 만들어서 사용하고자 하는 경우는 dealloc을 override 해야 하며 호출은 dealloc이 아니고 release를 사용하는 것이 바람직합니다.
01.
#import <Foundation/Foundation.h>
02.
@interface Test:NSObject
03.
-(
void
)dealloc;
04.
@end
05.
@implementation Test:NSObject
06.
-(
void
)dealloc
07.
{
08.
NSLog(@
"이 인스턴스의 메모리 공간이 완전히 해제됩니다"
);
09.
[super dealloc];
10.
}
11.
@end
12.
int
main()
13.
{
14.
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
15.
Test *obj = [[Test alloc] init];
16.
NSLog(@
"init: %d\n"
, [obj retainCount]);
//1
17.
[obj retain];
//2
18.
[obj release];
//1
19.
//dealloc은 직접 호출하는 것보다 release를 이용해서 retainCount를 0을 만들어서 호출하는 것이 바람직하다.
20.
[obj release];
//0이 되면서 dealloc이 호출됨
21.
[pool drain];
22.
return
0;
23.
}
결과
2010-11-09 10:46:24.035 DeallocCall[1115:a0f] init: 1
2010-11-09 10:46:24.037 DeallocCall[1115:a0f] 이 인스턴스의 메모리 공간이 완전히 해제됩니다
01.
//release 오류
02.
#import <Foundation/Foundation.h>
03.
int
main()
04.
{
05.
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc]init];
06.
id obj = [[NSObject alloc] init];
07.
NSLog(@
"init: %d\n"
, [obj retainCount]);
//1
08.
09.
id obj1 = obj;
// assign을 발생시키면 retainCount는 들어가기는 함.
10.
NSLog(@
"assign: %d\n"
, [obj retainCount]);
//1
11.
12.
//id obj1 = [obj retain];; //여기와 아래 줄이 없어야 에러발생
13.
//NSLog(@"retain: %d\n", [obj retainCount]);
14.
[obj release];
//현재 retainCount가 1이므로 릴리즈되면 0 -> dealloc을 호출함
15.
[obj1 release];
//release가 안된다 - 이미 해제된 상태
16.
//0이되면 dealloc을 호출하는데 여기서 릴리즈하면 -1이되므로 오류발생
17.
[pool drain];
18.
return
0;
19.
}
결과
2010-11-09 11:02:44.693 ReleaseError[1366:a0f] init: 1
2010-11-09 11:02:44.695 ReleaseError[1366:a0f] assign: 1
DeallocCall(1366) malloc: *** error for object 0x1001093f0: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
01.
//release 오류
02.
#import <Foundation/Foundation.h>
03.
int
main()
04.
{
05.
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc]init];
06.
id obj = [[NSObject alloc] init];
07.
NSLog(@
"init: %d\n"
, [obj retainCount]);
//1
08.
/*
09.
id obj1 = obj; // assign을 발생시키면 retainCount는 들어가기는 함.
10.
NSLog(@"assign: %d\n", [obj retainCount]); //1
11.
*/
12.
id obj1 = [obj retain];;
//여기와 아래 줄이 없어야 에러발생
13.
NSLog(@
"retain: %d\n"
, [obj retainCount]);
14.
[obj release];
//현재 retainCount가 1이므로 릴리즈되면 0 -> dealloc을 호출함
15.
[obj1 release];
//release가 안된다 - 이미 해제된 상태
16.
//0이되면 dealloc을 호출하는데 여기서 릴리즈하면 -1이되므로 오류발생
17.
[pool drain];
18.
return
0;
19.
}
결과
2010-11-09 11:03:14.614 ReleaseError[1392:a0f] init: 1
2010-11-09 11:03:14.616 ReleaseError[1392:a0f] retain: 2
NSHeader
NSString : 문자열
NSValue
NSDate
NSData
NSArray
NSSel
NSDictionary
%@ : 데이터의 description을 호출
5. 클래스와 객체의 설명
+(NSString *)description
클래스 이름을 문자열로 리턴
-(NSString *)description
클래스명과 id 값을 문자열로 리턴
주의할 점은 Foundation 클래스들은 오버라이딩이 되어 있는 경우도 있습니다.
01.
#import <Foundation/Foundation.h>
02.
@interface Test : NSObject
03.
@end
04.
@implementation Test
05.
@end
06.
int
main()
07.
{
08.
NSAutoreleasePool *pool = [NSAutoreleasePool
new
];
09.
Test *Obj = [[Test alloc] init];
10.
//클래스가 description을 호출하면 클래스 이름을 문자열로 리턴
11.
NSLog(@
"%@"
,[Test description]);
12.
//일반 객체가 description을 호출하면 클래스 이름과 id를 리턴
13.
NSLog(@
"%@"
,[Obj description]);
14.
//파일에 바로 저장이 되는 자료형의 데이터가 description을 호출하면
15.
//파일에 저장되는 형태를 문자열로 리턴
16.
NSLog(@
"%@"
,[@
"Hello"
description]);
17.
[pool drain];
18.
return
0;
19.
}
결과
2010-11-09 11:09:42.269 DescriptionTest[1449:a0f] Test
2010-11-09 11:09:42.271 DescriptionTest[1449:a0f] <Test: 0x100109080>
2010-11-09 11:09:42.271 DescriptionTest[1449:a0f] Hello
AutoreleasePool
Foundation을 이용하는 프로그램을 만들 때는 AutoreleasePool을 설정해서 사용해야 합니다.
시스템은 실제 메모리를 해제해야 할 Object에 대한 정보를 이 풀로부터 얻어오게 됩니다.
이 풀을 사용하려는 Object가 autorelease만 호출하면 자동으로 가장 가까운 풀에 등록이 됩니다.
alloc과 init으로 시작하는 메서드와 copy를 제외한 객체를 리턴하는 메서드는 전부 autorelease된 객체를 리턴합니다.
1) 생성
NSAutoreleasePool * 변수명 = [[NSAutoreleasePool alloc] init];
2) 해제
[변수명 drain];
alloc이나 copy를 제외한 메서드로 생성된 객체는 모두 autorelease된 객체이다.
[[NSNumber alloc] initWithInt:100]; //retainCount 는 1
-> 사용자가 해제해줘야 함. 메모리관리에 좋음. 웬만하면 이걸 사용할 것.
[[NSNumber numberWithInt:100]; //retainCount 는 1
-> autorelease pool이 자동으로 해제
--> main이 끝날 때까지 살아있게 되므로 메모리낭비 발생하므로 비추함.
01.
#import <Foundation/Foundation.h>
02.
@interface Test : NSObject
03.
@end
04.
@implementation Test
05.
@end
06.
int
main (
int
argc,
const
char
* argv[])
07.
{
08.
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
09.
Test *Obj=[[ Test alloc]init];
//alloc으로 만들어짐
10.
NSLog(@
"Obj retain count = %d"
, [Obj retainCount]);
//1
11.
[pool drain];
//drain되어도 1
12.
NSLog(@
"After pool drain = %d"
, [Obj retainCount]);
//1
13.
pool = [[ NSAutoreleasePool alloc] init];
14.
[Obj autorelease];
15.
NSLog(@
"After autorelease = %d"
, [Obj retainCount]);
//1
16.
[Obj retain];
17.
NSLog(@
"After pool drain = %d"
, [Obj retainCount]);
//2
18.
[pool drain];
//1
19.
NSLog(@
"After second pool drain = %d"
, [Obj retainCount]);
//1
20.
[Obj release];
21.
return
0;
22.
}
결과
2010-11-09 11:28:11.598 DeallocCall[1673:a0f] Obj retain count = 1
2010-11-09 11:28:11.600 DeallocCall[1673:a0f] After pool drain = 1
2010-11-09 11:28:11.601 DeallocCall[1673:a0f] After autorelease = 1
2010-11-09 11:28:11.601 DeallocCall[1673:a0f] After pool drain = 2
2010-11-09 11:28:11.602 DeallocCall[1673:a0f] After second pool drain = 1
01.
int
main (
int
argc,
const
char
* argv[])
02.
{
03.
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
04.
//num1은 alloc으로 생성했으므로 NSAutoreleasePool의 영향을 받지 않는다.
05.
//해제를 직접 해줘야 함.
06.
//num2는 alloc이나 copy가 아닌 메서드로 생성했으므로 NSAutoreleasePool의 영향을 받는다.
07.
//NSAutoreleasePool객체가 drain을 호출하거나 소멸될 때 자동적으로 release가 발생
08.
NSNumber * num1 = [[NSNumber alloc]initWithInt:100];
09.
NSNumber * num2 = [NSNumber numberWithInt:200];
10.
NSLog(@
"num1의 retainCount:%d"
,[num1 retainCount]);
// 1
11.
NSLog(@
"num2의 retainCount:%d"
,[num2 retainCount]);
// 1
12.
[pool drain];
//drain되므로 num2는 release를 수행해서 dealloc 됨.
13.
NSLog(@
"num1의 retainCount:%d"
,[num1 retainCount]);
14.
//메모리 해제가 발생했으므로 런타임 오류
15.
NSLog(@
"num2의 retainCount:%d"
,[num2 retainCount]);
//0이므로 오류발생
16.
[num1 release];
17.
return
0;
18.
}
결과
2010-11-09 11:33:05.222 DeallocCall[1747:a0f] num1의 retainCount:1
2010-11-09 11:33:05.224 DeallocCall[1747:a0f] num2의 retainCount:1
2010-11-09 11:33:05.228 DeallocCall[1747:a0f] num1의 retainCount:1
Program received signal: “EXC_BAD_ACCESS”.
sharedlibrary apply-load-rules all
alloc
init
new
retain
release
retainCount
autorelease
아이폰 어플 개발 중 메모리누수 탐지방법
Xcode-Run with Perfomence Tool - Leaks
NSDate
- 날짜와 시간에 관련된 클래스
- alloc과 init으로 초기화하면 현재 시간 및 날짜로 초기화가 수행됩니다.
- date 프로퍼티로 값을 리턴하거나 설정할 수 있습니다.
- description은 현재 날짜 및 시간을 GMT 기준으로 날짜 및 시간을 문자열로 리턴합니다.
- description에 locale을 지정해서 지역화 된 문자열로 리턴받을 수도 있습니다.
- 출력 서식은 일반적으로 NSDateFormatter를 이용해서 설정한 후 출력하는 것이 일반적입니다.
NSDateFormatter
날짜나 시간에 관련된 포맷을 지정할 수 있는 클래스
setDateStyle:(NSDateFormatterStyle)style => 날짜 서식 지정
setTimeStyle:(NSDateFormatterStyle)style => 시간 서식 설정
setDateFormat: 서식 포맷 설정 => 날짜나 시간을 사용자 정의 서식으로 설정
(NSDate *)dateFromString:(NSString *)string => 문자열로부터 날짜 얻기
(NSString *)stringFromDate:(NSDate *)date => 날짜로부터 문자열 얻기
(NSLocale *)locale => 현재 지역정보 리턴
setLocale:(NSLocale *)locale => 지역 정보 설정
01.
#import <Foundation/Foundation.h>
02.
int
main (
int
argc,
const
char
* argv[])
03.
{
04.
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
05.
NSDate * date = [[NSDate alloc]init];
06.
NSLog(@
"%@"
,date);
07.
08.
NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
09.
[dateFormatter setTimeStyle:NSDateFormatterFullStyle];
10.
NSLog(@
"%@"
,[dateFormatter stringFromDate:date]);
11.
[dateFormatter setDateFormat:@
"yyyy-MM-dd ccc HH:mm:ss"
];
12.
NSLog(@
"%@"
,[dateFormatter stringFromDate:date]);
13.
[dateFormatter release];
14.
[date release];
15.
[pool drain];
16.
return
0;
17.
}
결과
2010-11-09 12:18:18.399 time[2394:a0f] 2010-11-09 12:18:18 +0900
2010-11-09 12:18:18.411 time[2394:a0f] 오후 12시 18분 18초 KST
2010-11-09 12:18:18.412 time[2394:a0f] 2010-11-09 화 12:18:18
NSLocale
지역 설정을 할 수 있는 클래스
- (id)initWithLocaleIdentifier:(NSString *)string=> 지역 정보 생성
한국: ko_KR
미국: en_US
일본: ja_JP
+ systemLocale => 시스템의 지역 정보
+ currentLocale => 현재 지역 정보
01.
#import <Foundation/Foundation.h>
02.
int
main (
int
argc,
const
char
* argv[]) {
03.
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
04.
NSDate * date = [[NSDate alloc]init];
05.
NSLog(@
"%@"
,date);
06.
NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
07.
NSLocale * locale = [[NSLocale alloc] initWithLocaleIdentifier : @
"en_US"
];
08.
[dateFormatter setLocale:locale];
09.
[dateFormatter setDateStyle : NSDateFormatterLongStyle];
10.
[dateFormatter setTimeStyle : NSDateFormatterLongStyle];
11.
NSLog(@
"%@"
,[dateFormatter stringFromDate:date]);
12.
[dateFormatter release];
13.
[date release];
14.
[locale release];
15.
[pool drain];
16.
return
0;
17.
}