【问题标题】:UIAlertController memory leakUIAlertController 内存泄漏
【发布时间】:2016-01-11 23:51:49
【问题描述】:

我没有使用 ARC。

在展示 UIAlertController 时,通过 Instruments 测试泄漏给了我以下信息:

当我检查调用树时,它似乎在抱怨这段代码。不确定其中有多少是相关的,但无论如何......

-(void) connection:(NSURLConnection*)connection didFailWithError:(NSError*)error {
  // bunch of code

  #ifndef NDEBUG
    NSString* err_msg = [NSString stringWithFormat:@"%@%ld", @"Error number ", (long) error_code];
    // @property (nonatomic, retain) id <DownloadMonitor> m_downloadMonitor;
    [_m_downloadMonitor showDownloadAlert:err_msg withTitle:@"Download error"];
  #endif

m_downloadMonitor实际上是一个DashboardController类型的对象,定义如下:

@interface DashboardController : BaseController <UIAlertViewDelegate, UITableViewDelegate, UITableViewDataSource, DownloadMonitor>

DownloadMonitor是自定义协议,定义如下:

@protocol DownloadMonitor <NSObject>
-(void) downloadFinishedFor:(UIProgressView*)progress_bar;
-(void) downloadFailedFor:(UIProgressView*)progress_bar;
-(void) showDownloadAlert:(NSString*)message withTitle:(NSString*)title;
@end

方法showDownloadAlertDashboardController中定义如下:

-(void) showDownloadAlert:(NSString*)message withTitle:(NSString*)title {
  [self showPopupMessage:message withTitle:title andDelegate:self andActionHandlers:@{@"OK":@""}];
}

最后,BaseController 中的showPopupMessageDashboardController 的父类):

- (void)showPopupMessage: (NSString*)message withTitle:(NSString*)title andDelegate:(BaseController*)delegate andActionHandlers:(NSDictionary*)handlers {
  UIAlertController* alert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];

  for ( id key in handlers ) {
    NSString* button_name = (NSString*) key;
    NSString* handler_name = (NSString*) [handlers objectForKey:key];
    UIAlertAction* action;

    if ( ! [handler_name isEqualToString:@""] ) {
      SEL sel = NSSelectorFromString(handler_name);
      action = [UIAlertAction actionWithTitle:button_name style:UIAlertActionStyleDefault handler:^(UIAlertAction * action)         {
          [delegate performSelector:sel];
          [alert dismissViewControllerAnimated:YES completion:NULL];
        }];
    }
    else {
      action = [UIAlertAction actionWithTitle:button_name style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
      [alert dismissViewControllerAnimated:YES completion:NULL];
        }];
    }

    [alert addAction:action];
  }

  [delegate presentViewController:alert animated:YES completion:nil];
}

为什么 Instruments 会显示泄漏? 我查看了这些线程:

iOS 8 Only Memory Leak with UIAlertController or UIActionSheet

UIAlertController memory leak/issues - Swift

他们似乎暗示这可能是一个错误......或者它可能是我错过的保留周期。

【问题讨论】:

    标签: ios objective-c memory-leaks instruments


    【解决方案1】:

    我认为你有一个保留圈:

    showPopupMessage 方法中,动作被添加到alert 并保留它们。您定义引用 alert 的块(因为它使用它)。块正在保留alert

    所以,alert 保留了保留 `'alert: your retain circle!

    的块

    你应该试试:

    __block __typeof__(alert) blockAlert = alert;
    
    action = [UIAlertAction actionWithTitle:button_name style:UIAlertActionStyleDefault handler:^(UIAlertAction * action)         {
        [delegate performSelector:sel];
        [blockAlert dismissViewControllerAnimated:YES completion:NULL];
    }];
    

    __block 存储类型修饰符将引用警报而不保留它(在非 ARC 模式下):https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Blocks/Articles/bxVariables.html#//apple_ref/doc/uid/TP40007502-CH6-SW6

    【讨论】:

    • 谢谢!这似乎阻止了它报告相同的泄漏,但现在它对这条线感到不满:UIAlertController* alert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
    • 另外,我猜你的代码应该在[alert dismissViewControllerAnimated:YES completion:NULL];这一行替换alert
    • 是的,你是对的:我将delegate(这是我的第一个可疑变量)切换为alertdelegate必须保持原样,但 àlertmust be replaced with weak __blockref blockAlert`。如果我的答案是正确的,不要忘记将其标记为正确/接受的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-20
    • 2014-12-02
    • 1970-01-01
    • 1970-01-01
    • 2011-10-08
    • 2013-01-20
    相关资源
    最近更新 更多