2013-10-11 2 views
0

내 맞춤 주석 메서드에서 응용 프로그램이 중단되기 시작하면 메모리에 문제가 있다는 것을 알았습니다. 100 %지도의 viewcontroller를 관리하는 것이 뷰 스택에서 중단되어야한다고 확신했습니다.주석 dealloc 메서드는 ARC에서 호출되지 않았으며 기본 viewcontroller dealloc이 호출되었습니다

#import <Foundation/Foundation.h> 
@import MapKit; 

@interface TaxiArrivingAnnotation : NSObject<MKAnnotation> 
@property (nonatomic) CLLocationCoordinate2D coordinate; 
@property (nonatomic) int minutesToTaxiArrival; 

-(void) startTimer; 
@end 

TaxiArrivingAnnotation.m :

#import "TaxiArrivingAnnotation.h" 

#define SECONDS_IN_A_MINUTE 60 

@interface TaxiArrivingAnnotation() 
@property (nonatomic) NSTimer * timer; 
@property (nonatomic) NSDate * timeOfArrival; 
@property (nonatomic, weak) id token1; 
@property (nonatomic, weak) id token2; 
@end 

@implementation TaxiArrivingAnnotation 

- (id)init 
{ 
    self = [super init]; 
    if (self) { 
     __weak TaxiArrivingAnnotation * this = self; 

     self.token1 = [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidBecomeActiveNotification object:nil queue:nil usingBlock:^(NSNotification *note) 
     { 
      NSLog(@"DID BECOME ACTIVE"); 
      NSTimeInterval secondsLeft = [this.timeOfArrival timeIntervalSinceNow]; 
      if (secondsLeft < 0) { 
       self.minutesToTaxiArrival = 0; 
       return; 
      } 

      this.minutesToTaxiArrival = secondsLeft/SECONDS_IN_A_MINUTE; 

      [this startTimer]; 
     }]; 

     self.token2 = [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillResignActiveNotification object:nil queue:nil usingBlock:^(NSNotification *note) 
     { 
      NSLog(@"WILL RESIGN ACTIVE"); 
      [this.timer invalidate]; 
      this.timer = nil; 
     }]; 

    } 
    return self; 
} 


-(void) setMinutesToTaxiArrival:(int)newMinutes { 
    self->_minutesToTaxiArrival = newMinutes; 
    self->_timeOfArrival = [NSDate dateWithTimeIntervalSinceNow:SECONDS_IN_A_MINUTE * newMinutes]; 
    if (newMinutes < 0) { 
     [self.timer invalidate]; 
    } 
} 

-(void) startTimer { 
    self.timer = [NSTimer timerWithTimeInterval:SECONDS_IN_A_MINUTE target:self selector:@selector(aMinutedPassed) userInfo:nil repeats:YES]; 
    [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode]; 
} 

-(void) aMinutedPassed { 
    self.minutesToTaxiArrival--; 
} 

-(void) dealloc { 
    NSLog(@"DEALLOC"); 
    if (self.timer != nil && [self.timer isValid]) 
     [self.timer invalidate]; 
    [[NSNotificationCenter defaultCenter] removeObserver:self.token1]; 
    [[NSNotificationCenter defaultCenter] removeObserver:self.token2]; 
} 
@end 

내가 viewDidAppear에 주석을 추가하고 viewDidDisappear에 제거하고 여기에

TaxiArrivingAnnotation.h 주석에 대한 코드입니다. 뿐만 아니라 그것을 제거뿐만 아니라 nil - 참조를. 뷰 컨트롤러 dealloc을 관리 할 때 여전히 호출되지 않는 dealloc 메서드가 호출됩니다.

실제 문제는 주석이 할당 취소 되었기 때문에 타이머와 알림이 작동하지 않는 것입니다.

답변

1

invalidate 반복 타이머를 dealloc (으)로 시도하고 있습니다. 문제는 타이머가 target (주석)에 대한 강력한 참조를 유지하므로 dealloc이 더 이상 호출되지 않는 것입니다. 더 강력한 참조가 없을 때만 호출되기 때문입니다. 이는 강력한 참조주기 (a.k.a. retain cycle)와 유사합니다.

보기 컨트롤러가 할당 해제 될 때 (또는보기 컨트롤러의 해고를 시작하는 논리 이벤트가 무엇이든) 타이머가 invalidate이어야합니다. 그리고 타이머가 dealloc에 도달 할 때까지 무효화 될 것이므로, 분명히 dealloc 코드에서 invalidate 코드를 제거 할 수 있습니다.

+0

NSTimer가 실행될 때 내 주석이 죽은 이유는 무엇입니까? 그것이 내 사고 다. dealloc 메서드를 호출하지 않고도 개체가 죽을 수 있습니까? –

+1

@EvgeniPetrov 스택 추적없이 충돌을 진단하고/또는 위반 코드 행을 식별하기가 어렵습니다 (예 : [예외 중단 점] (https://developer.apple.com/library/ios/recipes/xcode_help-breakpoint_navigator/articles)). /adding_an_exception_breakpoint.html)). 어노테이션이 연관된 맵이 제거 된 후에도 주석이 유지된다면 문제는 상상할 수 있지만 말할 수는 없습니다. 충돌은 다른 것일 수 있습니다. 그러나 나는'target '의'dealloc'에서 반복 타이머를'무효화하려 시도하면 결코 작동하지 않을 것이라는 사실을 알고 있습니다. 이 문제를 해결하고 충돌이 사라지는지 확인하십시오. – Rob