简体   繁体   English

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

[英]Why does UIAlertController create a retain cycle with self?

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];

I understand the cycle . 我理解这个循环 self retains the UIAlertController , UIAlertController retains the UIAlertAction , UIAlertAction retains self self保留UIAlertControllerUIAlertController保留UIAlertActionUIAlertAction保留self

What I mean is internally couldn't this class have been designed to release everything after one of the UIAlertActions has been run? 我的意思是内部不能将这个类设计为在UIAlertActions运行之后释放所有内容吗?

- -

To clarify, I know that this issue can be avoided by using a weak reference to self. 为了澄清,我知道通过使用对自我的弱引用可以避免这个问题。

What I am asking is why doesn't UIAlertController just nil out all the actions (and hence their handler blocks) once an action has been selected by the user. 我要问的是,一旦用户选择了一个动作,为什么UIAlertController不会将所有动作(以及它们的处理程序块)都UIAlertController This would break the cycle and avoid the whole weakself dance we need to do. 这将打破周期,避免我们需要做的整个弱势舞蹈。

Something like this... 像这样......

@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
}

The question and answers here baffled me, and this is on top of my search results so I'd like to set the record straight: 这里的问题和答案令我感到困惑,这是我的搜索结果,所以我想直接记录:

There is no retain cycle in the example, so there is no need to create a "weak self" in this case. 示例中没有保留周期,因此在这种情况下不需要创建“弱自我”。 The only time that there's a retain cycle is if self has a strong reference on alert. 保留周期的唯一时间是自我是否具有强烈的警报参考。

UIAlertController has been designed to release everything after it has been executed, provided you don't hold a strong reference to it. UIAlertController被设计为在执行后释放所有内容,前提是您没有强有力的引用。

I tried the example in a sample class, and dealloc was successfully called on pop of the controller. 我在示例类中尝试了该示例,并且在控制器的pop上成功调用了dealloc。

To summarise by example: 通过例子总结:

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 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];

Side note: It's wrong to assume that you always need to use weak reference to self when putting it in blocks. 旁注:假设在将其放入块中时总是需要使用弱引用是错误的。

The issue is not how UIAlertController is designed, but how block works ie it captures/retains the reference object unless the reference variable is marked weak. 问题不在于UIAlertController的设计方式,而是块如何工作,即它捕获/保留引用对象,除非引用变量标记为弱。 I think changing the block code from [self doSomething]; 我想改变[self doSomething];的块代码[self doSomething]; to [weakSelf doSomething]; [weakSelf doSomething]; should fix the retain cycle. 应该修复保留周期。 Where the weakSelf variable can be declared before the action creation like below: weakSelf变量可以在动作创建之前声明,如下所示:

__weak YourViewCOntrollerClass *weakSelf = self;

Actually when we use strong instance in block( like you are using self ), it create the separate copy increase the retain count. 实际上当我们在块中使用强实例时(就像你正在使用self),它会创建单独的副本来增加保留计数。 After that class decrement the retain count by calling dealloc method. 在该类通过调用dealloc方法减少保留计数。 But cannot make it zero. 但不能使它为零。 weak reference release the count after its use. 弱引用在使用后释放计数。 so, create weak reference like this: 所以,创建这样的弱引用:

   __weak __typeof(self)weakSelf = self;

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

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

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