简体   繁体   English

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

[英]Annotation dealloc method never called in ARC, underlying viewcontroller dealloc is called

I learned that I have problem with memory when my app started crashing in my custom annotation method. 我了解到,当我的应用程序开始以我的自定义注释方法崩溃时,内存有问题。 I was sure managing viewcontroller of the map 100% should have been popped from the view stack. 我确定应该从视图堆栈中弹出100%管理地图的viewcontroller。

Here is the code for the annotation, TaxiArrivingAnnotation.h : 这是注释的代码TaxiArrivingAnnotation.h

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

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

-(void) startTimer;
@end

and TaxiArrivingAnnotation.m : 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

I am adding the annotation on viewDidAppear and removing it on viewDidDisappear . 我在viewDidAppear上添加注释,并在viewDidDisappear上将其删除。 Not only removing it but nil -ing the reference. 不仅消除,但nil -ing参考。 The dealloc method still not called when managing viewcontroller dealloc is called. 调用管理视图控制器dealloc时仍未调用dealloc方法。

The real problem is that the timer and notifications fire and app crashes because the annotation has been deallocated. 真正的问题是计时器和通知会触发并且应用程序崩溃,因为注释已被释放。

You are attempting to invalidate your repeating timer in dealloc . 您正在尝试invalidate dealloc的重复计时器invalidate The problem is that the timer keeps a strong reference to the target (your annotation), which will prevent dealloc from ever getting called (because it's only called when there are no more strong references). 问题在于计时器保留了对target (您的注释)的强引用,这将防止调用dealloc (因为只有在没有更多强引用时才调用dealloc )。 It's analogous to a strong reference cycle (aka retain cycle). 这类似于强大的参考周期(也称为保留周期)。

You have to invalidate the timer when your view controller is deallocated (or whatever the logical event is that initiates the dismissal of the view controller). 在释放视图控制器时(或引发关闭视图控制器的任何逻辑事件),必须invalidate计时器invalidate And since the timer will be invalidated by the time you get to dealloc , you can remove the invalidate code from the dealloc method of the annotation, obviously. 而且由于计时器将在您到达dealloc invalidate ,因此显然可以从注释的dealloc方法中删除invalidate代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM