【问题标题】:Annotation dealloc method never called in ARC, underlying viewcontroller dealloc is calledARC中从未调用过注解dealloc方法,调用底层viewcontroller dealloc
【发布时间】:2013-10-19 13:13:51
【问题描述】:

当我的应用程序在我的自定义注释方法中开始崩溃时,我了解到我的内存存在问题。我确信管理地图的视图控制器 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-ing 引用。管理视图控制器dealloc被调用时,dealloc方法仍然没有被调用。

真正的问题是,由于注释已被释放,计时器和通知会触发并且应用程序崩溃。

【问题讨论】:

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


    【解决方案1】:

    您正尝试在deallocinvalidate 您的重复计时器。问题是计时器保持对target(您的注释)的强引用,这将阻止dealloc 被调用(因为它仅在没有更多强引用时被调用)。它类似于强引用循环(又名保留循环)。

    当您的视图控制器被解除分配(或任何启动视图控制器解除的逻辑事件)时,您必须invalidate 计时器。而且由于计时器在到达dealloc 时会失效,因此显然可以从注解的dealloc 方法中删除invalidate 代码。

    【讨论】:

    • 那么为什么我的注释在 NSTimer 触发时会失效?这就是我的崩溃。如果不调用其 dealloc 方法,对象会死吗?
    • @EvgeniPetrov 在没有堆栈跟踪和/或识别有问题的代码行(例如exception breakpoint)的情况下很难诊断崩溃。如果在删除与之关联的地图后保留注释,我可以想象会出现问题,但我不能说。崩溃可能是别的东西。但我知道一个事实是,在targetdealloc 中尝试invalidate 重复计时器将永远不会起作用。修复这个问题,看看崩溃是否消失。
    猜你喜欢
    • 1970-01-01
    • 2013-02-28
    • 2013-04-28
    • 2015-04-06
    • 1970-01-01
    • 2011-12-17
    • 1970-01-01
    • 1970-01-01
    • 2014-01-13
    相关资源
    最近更新 更多