본문 바로가기
  • 그냥 하자
iOS

Chap4-2. enum,typedef,전처리기,preprocessor,define,전방선언,import,조건부컴파일,if,elif,배열,함수,구조체,sdk,nsobject,클래스,메모리생성,메모리해제,dealloc,autoreleasepool,nsdate,nsdateformatter,nslocale

by Mash 2012. 3. 22.
반응형


이 글은 아래의 출처를 수정하여 작성한 글 임을 밝힌다. 
<출처 : 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.}

반응형