2013-07-11 2 views
3

이 버그는 제 코드에서 며칠 동안 보였습니다. 문제를 해결하려고 노력했지만 아무 소용이 없었습니다. 나는 광범위한 디버깅을했고, 시뮬레이터와 장치, 로깅, 크래시 틱스 (crashlytics)가 크래시 로그를 던져 버렸고, 할당 해제 후 내 NSTimer 메시지와 관련이있다. 더 설명하겠습니다.앱이 포 그라운드로 돌아온 후 NSTimer가 충돌 함

일부 뷰 컨트롤러에이 NSTimer 컨트롤 내 UIToolbar 라벨, 그리고 사용자가 UITableView을 갱신 할 때의 상대 시간을 표시하는 라벨을 업데이트 유지. 로드 할 때마다 새로 고칠 때마다 Updated just now이 표시되고 사용자가 새로 고치거나 다른 VC로 이동하지 않으면 60 초마다 업데이트됩니다. 잠시 후에 Updated 1 minute ago이 표시됩니다. NSTimerUILabel을 업데이트하는 방법을 트리거합니다. 사용자 새로 고침 (새로 고침 컨트롤을 뽑음으로써)에서이 메서드는 내 getAllItems 내에서 수동으로 호출됩니다 (즉, nil을 전달하는 이유입니다).

NSTimer 나의 슈퍼 클래스에 정의되어

- (void)getAllItems 
{ 
    KILL_TIMER(self.updateDateTimer); 
    self.updateLabel = [Formatters boldLabelWithLabel:self.updateLabel 
              withText:@"Checking for items..." 
              withFont:[UIFont fontWithName:kOpenSansBold size:15.0f]]; 

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
     [self fetchObjectsWithRequest:self.request]; 
     sleep(1); 
     dispatch_async(dispatch_get_main_queue(), ^{ 
       [self.refreshControl performSelector:@selector(endRefreshing) withObject:nil afterDelay:0]; 

      self.updatedDate = [NSDate date]; 
      [self updateTimer:nil]; 
      self.updateDateTimer = [NSTimer scheduledTimerWithTimeInterval:kToolbarUpdateLabelInterval 
                    target:self 
                    selector:@selector(updateTimer:) 
                    userInfo:nil repeats:YES]; 
     }); 
    }); 
} 

KILL_TIMER(q) 같이, 내 슈퍼 클래스에 정의되어있다 : 이것은 내있는 tableview에 항목을 얻을 코드가

@property (nonatomic, weak) NSTimer *updateDateTimer; 

:

#define KILL_TIMER(q) if (q) {DDLogVerbose(@"KILLING TIMER: %@", q); [q invalidate]; q=nil;} 

이 정의는 다음 두 가지 방법으로 호출됩니다.

) 내 getAllItems 방법 : 그래서 내가 (viewDidLoad 또는 사용자가 테이블보기를 새로 고침하여 해당 메소드를 호출하여) 아이템을로드 할 때, 나는 항상 현재 타이머를 죽이려고 시도합니다. 항목을 가져오고 항목을 가져오고 '지금 업데이트 됨'을 표시 한 다음 타이머를 60 초마다 실행하도록 예약합니다. 등 각 viewWillDisappear`에

B) :

- (void)viewWillDisappear:(BOOL)animated 
{ 
    [super viewWillDisappear:animated]; 
    KILL_TIMER(self.updateDateTimer); 
} 

그러나, 나는 홈 버튼을 누르면, 다음 응용 프로그램을 다시 열 경우, 일반적으로 (항상, 내가보기 컨트롤러를 전환 한 경우에만) 다음과 같은 메시지와 충돌 (NSZombies와 함께 사용) :

2013-07-11 17:21:37.576 App[3923:907] *** -[ItemCDTVC setUpdateDateTimer:]: message sent to deallocated instance 0x20bc49f0 

내가 호출하는 NSNotification을해야합니까 내 getAllItems :

// Notification received when user returns to app (refreshes the table view) 
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(getAllItems) name:UIApplicationWillEnterForegroundNotification object:nil]; 

이것은 메뉴를 사용하여보기 컨트롤러를 전환하고 앱을 종료 한 후 다시 열면 (앱이 종료되지 않음) 발생합니다. 전환하는 뷰 컨트롤러의 수에 관계없이 사용자가 앱에 남아있는 경우 충돌이 발생하지 않습니다.

매우 재현하기는하지만 수정 방법은 잘 모르므로 매우 귀찮은 버그입니다. 어떤 도움을 주셔서 감사합니다.

+0

컨트롤러를 언제 옵저버에서 제거합니까? – Wain

+0

@Wain 당신은 이것을 의미합니까? '[[NSNotificationCenter defaultCenter] removeObserver : self]; '? 그렇다면, 나는이 코드를'dealloc'에 넣었다. – swiftcode

+0

알았어, 브레이크 포인트를 붙이고 때 맞춰. – Wain

답변

4

당신은 invalidating your timers when your app becomes inactive이어야합니다. -applicationWillResignActive:은 좋은 장소입니다. 앱이 다시 활성화되면 새 타이머를 만들 수 있습니다.

앱이 비활성 상태 일 때 타이머가 자동으로 종료되고 앱이 포 그라운드로 돌아가 더 이상 유효하지 않은 타이머에 액세스하려고 시도 할 때 충돌하기 때문에 앱이 충돌하는 것입니다.당신은 타이머를 무효화를 호출하면

+0

그건 그렇고, 나는'UIApplicationWillResignActiveNotification'에 대한'NSNotification'을 추가하고 타이머가 사직하기 전에 타이머를 죽여서 처리했습니다. 되돌아 오면'viewWillAppear'에서 타이머를 다시 만듭니다. 감사! – swiftcode

2

, 다시 사용할 수 없습니다 - How to "validate" a NSTimer after invalidating it?

을 내가 마음대로 "On/Off 스위치"할 수있는 타이머를 원한다면, 나는 BOOL useTimer 또는 무언가를 사용 반복 타이머의 경우 타이머가 실행되어야하는지 여부를 결정하는 정렬 유형입니다.

비 반복 타이머의 경우 새 타이머를 만듭니다.

관련 문제