为什么UIAlertController使用self创建保留周期?

时间:2017-06-01 03:25:40

标签: ios memory-management objective-c-blocks uialertcontroller retain-cycle

UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"alert" message:nil preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *action = [UIAlertAction actionWithTitle:@"action" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
    [self doSomething];
}];
[alert addAction:action];
[self presentViewController:alert animated:YES completion:nil];

我理解周期self保留UIAlertControllerUIAlertController保留UIAlertActionUIAlertAction保留self

我的意思是内部不能将这个类设计为在其中一个UIAlertActions运行后释放所有内容吗?

-

为了澄清,我知道通过使用对自我的弱引用可以避免这个问题。

我要问的是,一旦用户选择了某个操作,为什么UIAlertController不会将所有操作(以及它们的处理程序块)都清零。这将打破周期,避免我们需要做的整个弱势舞蹈。

像这样......

@implementation UIAlertController

...

// An action button was pressed
- (void)actionSelectedIndex:(NSInteger)index
{
    UIAlertAction *action = self.actions[index];
    action.handler(action); // Run the action handler block
    self.actions = nil; // Release all the actions
}

3 个答案:

答案 0 :(得分:9)

这里的问题和答案使我感到困惑,这是我的搜索结果,所以我想直接记录:

示例中没有保留周期,因此在这种情况下无需创建“弱自我”。保留周期的唯一时间是自我是否具有强烈的警报参考。

UIAlertController被设计为在执行后释放所有内容,前提是您没有强有力的引用。

我在示例类中尝试了这个示例,并且在控制器的pop上成功调用了dealloc。

通过例子总结:

UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"alert" message:nil preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *action = [UIAlertAction actionWithTitle:@"action" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
    //No retain cycle, no need for weak self
    [self doSomething];
}];
[alert addAction:action];
[self presentViewController:alert animated:YES completion:nil];

VS

//assume this is a strong reference
self.alert = [UIAlertController alertControllerWithTitle:@"alert" message:nil preferredStyle:UIAlertControllerStyleAlert];
__weak __typeof(self)weakSelf = self;
UIAlertAction *action = [UIAlertAction actionWithTitle:@"action" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
    //Need a weakSelf to avoid retain cycle
    [weakSelf doSomething];
}];
[self.alert addAction:action];
[self presentViewController:self.alert animated:YES completion:nil];

旁注:假设你把它放在块里总是需要使用弱引用是错误的。

答案 1 :(得分:1)

问题不在于UIAlertController的设计方式,而是块如何工作,即它捕获/保留参考对象,除非引用变量标记为弱。 我认为将块代码从[self doSomething];更改为[weakSelf doSomething];应该会修复保留周期。可以在创建动作之前声明weakSelf变量,如下所示:

__weak YourViewCOntrollerClass *weakSelf = self;

答案 2 :(得分:1)

实际上当我们在块中使用强实例时(就像你使用self一样),它会创建单独的副本来增加保留计数。在该类通过调用dealloc方法减少保留计数。但不能使它为零。 弱引用在使用后释放计数。所以,创建这样的弱引用:

set WshShell = WScript.CreateObject("WScript.Shell")  
set IE = CreateObject("InternetExplorer.Application") 
IE.Visible = False
IE.Navigate "http://myintranet/"