I am not using ARC.
Testing for leaks through Instruments gives me the following when presenting a UIAlertController:

It seems to be complaining about this block of code when I examine the call tree. Not sure how much of this is relevant but anyway...
-(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 is actually an object of type DashboardController, defined as follows:
@interface DashboardController : BaseController <UIAlertViewDelegate, UITableViewDelegate, UITableViewDataSource, DownloadMonitor>
DownloadMonitor is a custom protocol defined as follows:
@protocol DownloadMonitor <NSObject>
-(void) downloadFinishedFor:(UIProgressView*)progress_bar;
-(void) downloadFailedFor:(UIProgressView*)progress_bar;
-(void) showDownloadAlert:(NSString*)message withTitle:(NSString*)title;
@end
The method showDownloadAlert is defined in DashboardController as follows:
-(void) showDownloadAlert:(NSString*)message withTitle:(NSString*)title {
[self showPopupMessage:message withTitle:title andDelegate:self andActionHandlers:@{@"OK":@""}];
}
And finally, showPopupMessage in BaseController (the parent class of DashboardController):
- (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];
}
Why is Instruments displaying a leak? I had a look at these threads:
iOS 8 Only Memory Leak with UIAlertController or UIActionSheet
UIAlertController memory leak/issues - Swift
They seem to suggest it might be a bug...or it could be a retain cycle that I've missed.
I think you have a retain circle:
In showPopupMessage method, actions are added to alert which retains them. You define blocks that references alert (because it uses it). The blocks are retaining alert.
So, alert retains blocks which retain `'alert: your retain circle!
You should try:
__block __typeof__(alert) blockAlert = alert;
action = [UIAlertAction actionWithTitle:button_name style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
[delegate performSelector:sel];
[blockAlert dismissViewControllerAnimated:YES completion:NULL];
}];
The __block storage type modifier will reference alert without retaining it (in non-ARC mode): https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Blocks/Articles/bxVariables.html#//apple_ref/doc/uid/TP40007502-CH6-SW6
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With