UIAlertController 内存泄漏
UIAlertController memory leak
我没有使用 ARC。
通过 Instruments 测试泄漏在呈现 UIAlertController 时给我以下信息:
当我检查调用树时,它似乎在抱怨这段代码。不确定其中有多少是相关的,但无论如何...
-(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
方法showDownloadAlert
在DashboardController
中定义如下:
-(void) showDownloadAlert:(NSString*)message withTitle:(NSString*)title {
[self showPopupMessage:message withTitle:title andDelegate:self andActionHandlers:@{@"OK":@""}];
}
最后,BaseController
中的 showPopupMessage
(DashboardController
的父 class):
- (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
他们似乎暗示这可能是一个错误......或者它可能是我错过的保留周期。
我认为你有一个保留圈子:
在 showPopupMessage
方法中,动作被添加到 alert
并保留它们。您定义引用 alert
的块(因为它使用它)。这些块保留 alert
.
因此,alert
保留保留`'警报的块:您的保留圈!
你应该试试:
__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
我没有使用 ARC。
通过 Instruments 测试泄漏在呈现 UIAlertController 时给我以下信息:
当我检查调用树时,它似乎在抱怨这段代码。不确定其中有多少是相关的,但无论如何...
-(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
方法showDownloadAlert
在DashboardController
中定义如下:
-(void) showDownloadAlert:(NSString*)message withTitle:(NSString*)title {
[self showPopupMessage:message withTitle:title andDelegate:self andActionHandlers:@{@"OK":@""}];
}
最后,BaseController
中的 showPopupMessage
(DashboardController
的父 class):
- (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
他们似乎暗示这可能是一个错误......或者它可能是我错过的保留周期。
我认为你有一个保留圈子:
在 showPopupMessage
方法中,动作被添加到 alert
并保留它们。您定义引用 alert
的块(因为它使用它)。这些块保留 alert
.
因此,alert
保留保留`'警报的块:您的保留圈!
你应该试试:
__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