아이폰어플개발정보2010. 8. 23. 09:37
[펌] 쓰레드 기초

아아폰에서 모든 어플리케이션은 기본적으로 하나의 쓰레드를 가지고 있다. 이 쓰레드는 UIApplication 클래스에서 자동으로 생성하며 프로그램의 메인 룹이 이곳에서 실행된다. 하지만 어떤 작업이 그 작업을 마치는데 너무 오랜 시간이 걸린다면 그 작업을 새로은 쓰레드로 만들어서 실행하는 것이 좋다. 메인 쓰레드는 기본적으로 사용자와 상호 작용을 해야하는데, 어떤 작업이 시간을 너무 소모하면 사용자가 프로그램이 멈춘 것으로 오해 할 수 있다.

아이폰 OS 에서 쓰레드는 리눅스와 유닉스에서 지원하는 POSIX 쓰레드를 그대로 이용할 수 있다. 또한 코코아 터치 프레임워크 자체에서도 NSThread 라는 클래스를 이용해서 쓰레드를 좀 더 편리하게 생성할 수 있게 해 준다. 만약 이미 POSIX 로 작성된 코드를 가지고 있는 경우라면 새롭게 NSThread로 포팅하지 않고 바로 사용하는 것이 좋을 것이다.

이제 부터 코코아 터치가 제공하는 쓰레드 기능을 하나씩 구현해 보도록하자. POSIX 쓰레드는 이책에서는 따로 설명하지 않겠다.

* 쓰레드 생성하기

먼저 NSThread 객체를 이용해서 쓰레드를 생성해 보자. 다음은 NSThread 의 클래스 메서드를 이용하는 방법이다.

01: [NSThread
02: detachNewThreadSelector:@selector(threadFunc:)
03: toTarget:self
04: withObject:nil
05: ];

detachNewThreadSelector 메서드는 지정한 객체의 메서드를 이용해서 새로운 쓰레드를 생성해 준다. 위 코드에서 생성된 쓰레드는 바로 실행을 시작한다. 다음은 쓰레드를 생성하는 다른 방법이다.

01: NSThread* myThread = [[NSThread alloc]
02: initWithTarget:self
03: selector:@selector(threadFunc:)
04: object:nil
05: ];
06: [myThread start];

위 코드는 alloc, init 으로 생성을 먼저 한 후에 실행은 나중에 start 메서드를 호출할때 하도록 할 수 있다.

마지막으로 NSObject 를 이용해서 쓰레드를 생성하는 방법도 있다.

01: [objectA
02: performSelectorInBackground:@selector(doSomething)
03: withObject:myName];

 

* 쓰레드 메서드 구현하기

쓰레드에서 실행될 메서드는 다음과 같이 정의한다. 전달되는 인자는 쓰레드를 생성할 때 설정했던 object 가 넘어온다.

01: - (void)doSomething:(NSString*)name {
02: NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
03:
04: // 작업
05:
06: [pool release];
07: }

오토릴리즈(autoreleae) 풀은 객체 중에서 autorelease 메서드를 호출해서 생성된 객체들을 관리한다. 오토릴리즈 풀을 생성하면 그 이후로 생성되는 모든 autorelease 객체를 마지막에 생성된 오토릴리즈 풀 객체가 관리한다. 그리고 오토릴리즈 풀을 해제(release) 하면 이때 모든 오토릴리즈 객체도 같이 해제된다.

모든 쓰레드는 자신만의 오토릴리즈 스택을 관리하기 때문에, 쓰레드를 생성한 후 반드시 오토릴리즈 풀을 생성해야 한다.

* 런 루프

런 루프는 쓰레드가 외부와 통신하기 위해서 존재한다. 런 루프는 자신(쓰레드)에게 전달된 이벤트가 있는지를 검사하고, 만약 존재하는 경우 알맞은 메서드를 호출해 준다. 런 루프가 처리하는 이벤트는 크게 두가지가 있다.

• 입력 소스
    • performSelector:: 계열의 메서드를 호출해서 지정한 셀렉터를 실행시켜달라는 외부의 요청.
• 타이머
    • 타이머를 생성하면 그 타이머는 코드가 실행된 쓰레드의 런 루프에 소속된다. 런 루프는 타이머중에서 지정한 시간이 경과한 것들을 검사해서 메서드를 호출해 준다.

다음 코드를 보자.

01: if ( tapCount == 2) {
02: // 5개 모두 보여주자.
03: [self performSelector:@selector(showAllCircles) withObject:nil afterDelay:0.3];
04: NSLog(@"Scheduled");
05: }
06: ... 생략 ...
07: if (tapCount > 2) {
08: [UIView cancelPreviousPerformRequestsWithTarget:self];
09: NSLog(@"Cancelled");
10: }

이때 이미 쓰레드에 입력 소스를 추가하는 작업을 구현한 것이다. performSelector:withObject:afterDelay 메서드를 호출하면 현재 쓰레드의 런 루프에 입력 소스로써 등록이 된다. 그리고 런 루프가 실행될 때 자신에게 등록된 모든 입력 소스를 검사해서 조건이 만족되는 (여기서는 0.3초 경과) 경우 해당 메서드를 호출(예제에서는 showAllCircles)해 주는 것이다.

만약 스스로 쓰레드를 생성했다면 런 루프가 자동으로 실행되지는 않는다. 그래서 자신의 쓰레드 함수에서 직접 런 루프를 실행시켜서 주기적으로 외부의 이벤트에 대응할 수 있도록 만들어야 한다. 하지만 쓰레드가 하나의 작업만 수행하고 종료되는 경우라면 반드시 필요하지는 않다. 하지만 무한 루프를 돌면서 지속적으로 상호작용이 필요한 쓰레드라면 반드시 런 루프를 실행해 주도록 하자.

01: - (void)doSomething:(NSString*)name {
02: NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
03:
04: NSRunLoop* myRunLoop = [NSRunLoop currentRunLoop];
05: BOOL stop=NO;
06:
07: while(!stop) {
08: // 작업
09: [myRunLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
10: }
11:
12: [pool release];
13: }

4행에서 현재 쓰레드의 런 루프를 얻어온다. 그리고 9행에서 런 루프를 실행시킨다. 이 때 runIntilDate 메서드는 지정한 시간까지 런 루프를 실행시켜 준다. 하지만 런 루프가 아무런 할 일이 없다면 바로 종료된다.

* 쓰레드의 대안

쓰레드를 생성하는 코드를 직접 작성하지 않고도 간접적으로 쓰레드를 생성하게 할 수 있다. 이때 NSInvocationOperation 객체를 이용한다.

01: NSInvocationOperation* op =
02: [[[NSInvocationOperation alloc]
03: initWithTarget:self
04: selector:@selector(myMethod:) object:data] autorelease];

위 코드는 NSInvocationOperation 객체를 생성해 준다. 다음으로 할 일은 동작을 시작시키는 일이다.

01: NSOperationQueue* queue = [[NSOperationQueue alloc] init];
02: [queue setMaxConcurrentOperationCount:1];
03: [queue addOperation:op];

위 코드와 같이 NSOperatonQueue 객체를 생성하고 그 객체에 작업을 등록해 주면 된다.

[출처: http://maclove.pe.kr/30]



출처 : http://blog.naver.com/PostView.nhn?blogId=baek2187&logNo=150059860556
Posted by 오늘마감

댓글을 달아 주세요