从未在ARC中调用注释dealloc方法,调用底层的viewcontroller dealloc

时间:2013-10-11 12:42:18

标签: ios map automatic-ref-counting mapkit mkannotation

当我的应用程序开始在我的自定义注释方法中崩溃时,我了解到内存有问题。我确信应该从视图堆栈中弹出100%的地图控制器。

以下是注释的代码TaxiArrivingAnnotation.h

#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上删除它。不仅要删除它,还要nil - 引用。调用管理viewcontroller dealloc时仍未调用dealloc方法。

真正的问题是计时器和通知会崩溃并且应用程序崩溃,因为注释已被解除分配。

1 个答案:

答案 0 :(得分:1)

您正在invalidate尝试dealloc重复计时器。问题是计时器保留了对target(您的注释)的强引用,这将阻止dealloc被调用(因为只有在没有更多强引用时才调用它)。它类似于强引用循环(a.k.a.保留循环)。

在取消分配视图控制器时(或者启动解除视图控制器的逻辑事件),您必须invalidate计时器。由于到达dealloc时计时器将无效,因此您可以从注释的invalidate方法中删除dealloc代码。