第二次将非 nil 对象设置为弱 属性 returns nil 但不是第一次

Setting a non-nil object to a weak property returns nil second time but not first one

我正在开发一个我正在重构的遗留应用程序,并且有一个我不理解的奇怪行为。

有一个名为 CANoContentViewControllerUIViewController,它有一个来自 Nib 的简单初始化代码:

+ (CANoContentViewController *)instantiateController {
   CANoContentViewController *vc = [[CANoContentViewController alloc] initWithNibName:@"CANoContentViewController" bundle:[NSBundle mainBundle]];
   DLog(@"Created CANoContentViewController %@", vc);
   return vc;
}

然后,otherUIViewController没有内容显示就显示。这是代码:

@property (nonatomic, weak) UIViewController *noContentViewController;

-(void)showOrDeleteNoContentIfNeeded{
   if([self.proposals count] <= 0) { // Show No Content VC
       self.noContentViewController = [CANoContentViewController instantiateController];
       DLog(@"Set CANoContentViewController %@", self.noContentViewController);
       self.noContentViewController.view.frame = self.view.bounds;
       [self addChildViewController:self.noContentViewController];
       [self.view addSubview:self.noContentViewController.view];
       [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone];
   } else {
       [self.noContentViewController.view removeFromSuperview];
       [self.noContentViewController removeFromParentViewController];
       [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleSingleLine];
   }
}

这里的问题是第一次显示 CANoContentViewController,一切正常,日志符合预期:

2018-06-12 00:58:29.303276+0200 Base[11828:838463] +[CANoContentViewController instantiateController](0x105cc6688) Created CANoContentViewController <CANoContentViewController: 0x7fc350e101f0>
2018-06-12 00:58:29.303517+0200 Base[11828:838463] -[CAProposalsViewController showOrDeleteNoContentIfNeeded](0x7fc35106b200) Set CANoContentViewController <CANoContentViewController: 0x7fc350e101f0>

如您所见,创建的控制器在属性中设置正确。

第二次执行此代码,即使是将实例化 CANoContentViewController 的父视图控制器的新实例,CANoContentViewController 已正确创建,如日志所示,但未设置为属性:

2018-06-12 00:58:31.379708+0200 Base[11828:838463] +[CANoContentViewController instantiateController](0x105cc6688) Created CANoContentViewController <CANoContentViewController: 0x7fc350c8bca0>
2018-06-12 00:58:31.380275+0200 Base[11828:838463] -[CAProposalsViewController showOrDeleteNoContentIfNeeded](0x7fc35181f200) Set CANoContentViewController (null)

所以应用程序崩溃是因为它试图在方法 addChildViewController 中设置一个 nil 对象。

任何人都知道为什么这条线第二次不起作用并且 属性 是 nil?

self.noContentViewController = [CANoContentViewController instantiateController];

我检查过当我将 属性 更改为 strong 时一切正常。但我不明白为什么会这样,因为每次从新的父视图控制器创建 CANoContentViewController 时,self.noContentViewController 属性 应该与前一个不同。

执行后:

self.noContentViewController = [CANoContentViewController instantiateController];

不再有对您创建并分配给弱 属性 的对象的强引用,因此它被释放并且弱 属性 变为零。第一次成功只是运气,不能指望。

如果您希望实例存活足够长的时间以在该方法中对其进行处理,请分配给局部变量。

-(void)showOrDeleteNoContentIfNeeded{
   if([self.proposals count] <= 0) { // Show No Content VC
       CANoContentViewController *controller = [CANoContentViewController instantiateController];
       self.noContentViewController = controller;
       DLog(@"Set CANoContentViewController %@", self.noContentViewController);
       self.noContentViewController.view.frame = self.view.bounds;
       [self addChildViewController:self.noContentViewController];
       [self.view addSubview:self.noContentViewController.view];
       [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone];
   } else {
       [self.noContentViewController.view removeFromSuperview];
       [self.noContentViewController removeFromParentViewController];
       [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleSingleLine];
   }
}

局部变量的使用会在局部变量作用域内保持强引用。这会将引用保持足够长的时间来调用 addChildViewController,从而创建另一个强引用。

将您的 属性 设置为 strong 引用应该可行,因为该引用未被释放,因为它仍然保留着一个引用指针。

例如设置:

@property (nonatomic, strong) UIViewController *noContentViewController

而不是:

@property (nonatomic, weak) UIViewController *noContentViewController