为什么我的NSNotificationObserver在消息运行时被解除分配?

时间:2014-01-16 15:30:58

标签: ios objective-c automatic-ref-counting nsnotificationcenter

我遇到的情况是,当观察者处理传入的通知时,会删除对观察者的最后一个强引用。

这导致观察者立即被解除分配。我通常希望,当前运行的方法可以在取消分配对象之前完成。这就是正常消息发送过程中发生的情况。

代码的简化版本:

TKLAppDelegate.h:

#import <UIKit/UIKit.h>
#import "TKLNotificationObserver.h"

@interface TKLAppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) TKLNotificationObserver *observer;

@end

TKLAppDelegate.m:

#import "TKLAppDelegate.h"

@implementation TKLAppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

  // Create an observer and hold a strong reference to it in a property
  self.observer = [[TKLNotificationObserver alloc] init];

  // During the processing of this notification the observer will remove the only strong reference
  // to it and will immediatly be dealloced, before ending processing.
  [[NSNotificationCenter defaultCenter] postNotificationName:@"NotificationName" object:nil];

  // Create an observer and hold a strong reference to it in a property
  self.observer = [[TKLNotificationObserver alloc] init];

  // During the manual calling of the same method the observer will not be dealloced, because ARC still
  // holds a strong reference to the message reciever.
  [self.observer notificationRecieved:nil];

  return YES;
}

@end

TKLNotificationObserver.m:

#import "TKLNotificationObserver.h"
#import "TKLAppDelegate.h"

@implementation TKLNotificationObserver

- (id)init {
  if (self = [super init]) {
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notificationRecieved:) name:@"NotificationName" object:nil];
  }
  return self;
}

- (void)notificationRecieved:(NSNotification *)notification {
  [self doRemoveTheOnlyStrongReferenceOfThisObserver];
  NSLog(@"returing from notification Observer");
}

- (void)doRemoveTheOnlyStrongReferenceOfThisObserver {
  TKLAppDelegate * delegate = [[UIApplication sharedApplication] delegate];
  delegate.observer = nil;
}

- (void)dealloc {
  [[NSNotificationCenter defaultCenter] removeObserver:self name:@"NotificationName" object:nil];
  NSLog(@"dealloc was called");
}

@end

以这种方式使用App Delegate并不是一种好的风格,仅用于演示目的,真正的代码不涉及app委托。

输出结果为:

 dealloc was called
 returing from notification Observer
 returing from notification Observer
 dealloc was called

在第一种情况下,在通知处理完成之前调用dealloc。在第二种情况下,它的行为与我预期的一样。

如果我在notificationReceived内强烈提及自我,那么dealloc只会在处理之后发生。我的期望是,ARC,运行时或其他任何人都为我保留了这个强大的参考。

我的代码出了什么问题? 或者我的期望有问题吗? 是否有Apple或Clang提供的文件?

2 个答案:

答案 0 :(得分:3)

  

我的期望是,ARC,运行时或其他人保留这个   对我来说很有帮助。

情况并非如此,如Clang/ARC documentation中所述:

  

Objective-C方法的self参数变量实际上永远不会   由实施保留。它是未定义的行为,或者至少是   危险,导致在发送消息期间释放对象   那个对象。

因此,如果致电doRemoveTheOnlyStrongReferenceOfThisObserver 你可能必须使用释放self的副作用 一个临时的强引用,以避免重新分配:

- (void)notificationRecieved:(NSNotification *)notification {
   typeof(self) myself = self;
   [self doRemoveTheOnlyStrongReferenceOfThisObserver];
   NSLog(@"returing from notification Observer");
}

更好的解决方案可能是避免这种副作用。

答案 1 :(得分:0)

第一个dealloc可能发生在你将appDelegate的observer属性设置两次,因此第一次实例在第二次设置时就会被释放