2010-07-22 2 views
0

간단한 스레딩 예제에 문제가 있습니다. 내 방법이 완전하지는 않다는 것을 알지만, 지금부터는 시작 버튼을 누르고 매초마다 카운터를 증가시키는 스레드에서 그 불을 끄고 싶습니다. NSLog가 내 timerThread 메소드에 도착한다고 알려주기 때문에 그것이 IB에 올바르게 연결되어 있다는 것을 알고 있습니다. 그런 다음 updateDisplay 메서드에 도달하지 않고 즉시 초기 myThread로 바로 이동하고 풀을 해제합니다. 따라서 내 프로그램이 실제로 카운터를 증가시키지 않는다고 추측합니다. 나는 잠자 지 않은 간격이나 뭔가에 넣을 것이라고 생각했지만, 결국 나는 이것을 달성하기위한 올바른 방법을 놓치고 있다고 생각합니다. 어떤 생각이라도 좋을 것입니다. 감사!iphone threads 초급 질문, 자동 풀 풀 관리에 문제가 있습니다.

@implementation MainController 

-(id)initWithLabel:(UILabel *)label { 

    if (self = [super init]) { 
     countLabel = label; 
     [countLabel retain]; 
    } 
    return self; 
} 

-(int)count { 
    return count; 
} 

-(void)setCount:(int) value { 
    count = value; 
} 

-(void)updateDisplay:(NSTimer *)timer { 
    NSLog(@"%s", __FUNCTION__); 
    countLabel.text = [NSString stringWithFormat:@"%i", count]; 
    count++; 
} 

-(void)timerThread { 
    NSLog(@"%s", __FUNCTION__); 
    [NSTimer timerWithTimeInterval:1.0 
          target:self 
          selector:@selector(updateDisplay:) 
          userInfo:nil 
          repeats:YES]; 
    //NSNumber *threadID = [NSNumber numberWithInt:(int)threadID]; 

// threadLabel = [NSString stringWithFormat:@"%@", threadID]; 
} 

-(void)myThread { 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
    //NSNumber *threadID = [NSNumber numberWithInt:(int)threadID]; 
    [self performSelectorOnMainThread:@selector(timerThread) 
          withObject:nil 
         waitUntilDone:NO]; 
// NSLog(@"threadID in myThread: %@", threadID); 
    [pool release]; 
} 

-(void)startThread { 
// threadIndex = 0; 
// numThreads = 0; 
// NSNumber *threadID = [NSNumber numberWithInt:threadIndex++]; 
    [self performSelectorInBackground:@selector(myThread) withObject:nil]; 
// NSLog(@"%i", threadIndex); 
    numThreads++; 
} 

-(void)myThreadStop { 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
    [NSThread exit]; 
    [self performSelectorOnMainThread:@selector(updateDisplay) 
          withObject:nil 
         waitUntilDone:NO]; 

    [pool release]; 
} 

-(void)stopThread { 
    [self performSelectorInBackground:@selector(myThreadStop) withObject:nil]; 
} 

-(void) dealloc { 
    [countLabel release]; 
    [super dealloc]; 
} 

@end 
+0

내가 원하는 것은 스레드가 필요하지 않은 것 같습니다. NSTimer 만 있으면됩니다. – ohho

+1

예, 스레드를 제거하십시오. 그들은 당신이 틀린 경우에 당신에게 각종 문제를 일으키는 원인이 될 수있는 진보 된 기술이다. 타이머의 경우 drawonward의 대답은 우수합니다. –

답변

2

짧은 대답은 당신이 타이머를 예약하지 않았다는 것입니다.

iOS (및 기타)는 실행 루프를 사용합니다. 각 스레드에는 실행 루프가있을 수 있으며 기본 UI 스레드에는 실행 루프가 설정되어 있습니다. 간단히 말해, 실행 루프는 수행 할 작업의 대기열을 유지하고 수행 할 작업이있을 때까지 순서대로 수행하거나 블록합니다.

UILabel의 텍스트 설정과 같이 활성 UI로 수행하는 작업은 모두 주 스레드에서 수행해야합니다. 귀하의 경우 타이머를 업데이트하기 위해 주 스레드에 타이머를 설정했습니다 (예약하지는 않았습니다). 타이머를 예약한다는 것은 실행 루프에 타이머를 추가하는 것을 의미합니다.

마지막으로 UI를 업데이트하는 작업이 오래 걸린 경우 performSelectorInBackground를 사용하여 긴 작업을 시작하고 작업 업데이트 UI 완료시 performSelectorOnMainThread를 사용할 수 있습니다.

시계 나 카운터 UI를 업데이트하는 것과 같은주기적인 작업이 짧은 경우 타이머를 시작하려는 동일한 스레드에 NSTimer를 만들면됩니다. 타이머를 만들 때 scheduledTimerWithTimeInterval 변형을 사용하면 자동으로 시작됩니다.

반복 타이머를 만들 때 대상을 해제하기 전에 타이머를 무효화 할 수 있도록 반복 타이머를 참조해야합니다. 늦어도 dealloc에서는 타이머를 무효화해야합니다.

startThread를 호출하는 대신 timerThread를 startTimer로 변환하십시오.

-(void) startTimer { 
    timerMember = [[NSTimer 
     scheduledTimerWithTimeInterval:1.0 
           target:self 
          selector:@selector(updateDisplay:) 
          userInfo:nil 
          repeats:YES] retain]; 
} 

-(void) dealloc { 
    [timerMember invalidate]; 
    [timerMember release]; 
    ... 
}