I have searched for this problem but didn't get any proper solution. In my application I am giving multiple recursive Asynchronous calls to server. I am using the MKNetworkKit for performing network operation. Pseudocode of my implementation:
- updateForms{
[networkcall completionblock:^(MKNetworkOperation *op){
dictionaryObject = op.responseJSON
if(moreForms)
[self updateForms] // recursive call
else
save data in db and proceed further
}
}
However while executing above code memory usage is getting increased by 4 - 10 MBs after each call in completion block(I think on line dictionaryObject = op.responseJSON).
After using instruments, it is showing memory leak at line NSJSONSerialization JSONObjectWithData in MKNetworkKit function:
Following is the actual code I have written:
- (void)updateForms:(int)requestCount
{
/* ====================================
* update forms from webserver
* ====================================
*
*/
__block int blockRequestCount = requestCount;
if (UIApplication.sharedApplication.applicationState != UIApplicationStateActive)
{
NSLog(@"Background time remaining = %.1f seconds", [UIApplication sharedApplication].backgroundTimeRemaining);
}
// get username and password
NSString *username = [[NSUserDefaults standardUserDefaults] valueForKey:@"username"];
NSString *userPassword = [[NSUserDefaults standardUserDefaults] valueForKey:@"password"];
NSString *signature = [NSString stringWithFormat:@"url=%@&action=forms×tamp=%@", apiBaseURL, [[Utility shareInstance] getCurrentTimeStamp]];
//signature = [[Utility shareInstance] encodeWithURL:signature];
NSString *signatures = [[NSString alloc] initWithString:[[Utility shareInstance] hmacSHA256ForKeyAndData:request_PrivateKey withData:signature]];
NSString *timestamp = [[NSString alloc] initWithString:[[Utility shareInstance] getCurrentTimeStamp]];
NSMutableDictionary *dic = [[NSMutableDictionary alloc]init];
[dic setValue:apiBaseURL forKey:@"url"];
[dic setValue:timestamp forKey:@"timestamp"];
[dic setValue:signatures forKey:@"signature"];
[dic setValue:[NSString stringWithFormat:@"%d",requestCount] forKey:@"request_no"];
NSString *urlGetForms = [NSString stringWithFormat:@"%@forms", apiBaseURL];
//[MMProgressHUD setPresentationStyle:MMProgressHUDPresentationStyleFade];
//[MMProgressHUD showWithTitle:@"iPEGS" status:@"Loading..."];
if (UIApplication.sharedApplication.applicationState != UIApplicationStateActive)
{
NSLog(@"Background time remaining = %.1f seconds", [UIApplication sharedApplication].backgroundTimeRemaining);
}
//dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
__weak typeof(self) weakSelf = self;
//asynchronous code
[[AppRequest shareInstance] loadRequestWithURL:urlGetForms withLoadingIndicator:NO username:username password:userPassword params:dic success: ^(MKNetworkOperation *op) {
//dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
typeof(weakSelf) strongSelf = weakSelf;
if (op != nil){
if (UIApplication.sharedApplication.applicationState != UIApplicationStateActive){
NSLog(@"Background time remaining = %.1f seconds", [UIApplication sharedApplication].backgroundTimeRemaining);
}
// code modified
NSMutableDictionary *responseDataTemp;
@autoreleasepool {
NSDictionary *dic = op.responseJSON;
responseDataTemp = [[NSMutableDictionary alloc] initWithDictionary:dic];
}
//NSLog(@"responseData:%@\n\n\n",op.responseString);
[responseDataTemp removeObjectForKey:@"message"];
[responseData addEntriesFromDictionary:responseDataTemp];
if ([[responseDataTemp objectForKey:@"form_remaining"] intValue]) {
[responseData removeObjectForKey:@"form_remaining"];
NSLog(@"Custom Forms count %lu",(unsigned long)[responseData count]);
[strongSelf updateForms:++blockRequestCount];
}else{
[responseData removeObjectForKey:@"form_remaining"];
NSLog(@"Custom Forms count %lu",(unsigned long)[responseData count]);
// Parse response data and save in database
[strongSelf parseAndSaveData:strongSelf];
if (strongSelf.backgroundTask != UIBackgroundTaskInvalid){
[[UIApplication sharedApplication] endBackgroundTask:strongSelf.backgroundTask];
strongSelf.backgroundTask = UIBackgroundTaskInvalid;
}
dispatch_async(dispatch_get_main_queue(), ^{
//synchronous code
[MMProgressHUD dismiss];
[responseData removeAllObjects];
[customFormIds removeAllObjects];
[questionnaireIds removeAllObjects];
});
if (UIApplication.sharedApplication.applicationState != UIApplicationStateActive)
{
NSLog(@"Background time remaining = %.1f seconds", [UIApplication sharedApplication].backgroundTimeRemaining);
}
}
}
} failure: ^(MKNetworkOperation *op, NSError *er) {
if (er) {
if (self.backgroundTask != UIBackgroundTaskInvalid){
[[UIApplication sharedApplication] endBackgroundTask:self.backgroundTask];
self.backgroundTask = UIBackgroundTaskInvalid;
}
dispatch_async(dispatch_get_main_queue(), ^{
//synchronous code
[MMProgressHUD dismiss];
[responseData removeAllObjects];
[customFormIds removeAllObjects];
[questionnaireIds removeAllObjects];
});
}
//NSLog(@"error:%@", er.description);
if (self.backgroundTask != UIBackgroundTaskInvalid){
[[UIApplication sharedApplication] endBackgroundTask:self.backgroundTask];
self.backgroundTask = UIBackgroundTaskInvalid;
}
if (UIApplication.sharedApplication.applicationState != UIApplicationStateActive){
NSLog(@"Background time remaining = %.1f seconds", [UIApplication sharedApplication].backgroundTimeRemaining);
}
}];
}
I have added weak reference for self and also using autorelease block but it is not solving my issue.
What can I do to remove that memory leak or am I doing something wrong while doing recursive asynchronous calls?
Thanks!