2

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:

Please refer instruments screenshot showing memory leak

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&timestamp=%@", 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!

ViruMax
  • 1,216
  • 3
  • 16
  • 41
  • you have defined a weak self, but you still using self in block. That seems the issue – rishi Sep 30 '15 at 07:21
  • oh correct! but actually I have added that function call to replace lot of parsing code to keep question in readable format while adding it to stackoverflow. Actually I had also tried without that function call means with actual code written there it self but issue was there at that time also. And one more thing the memory usage is getting increased before reaching that line means while making recursive calls. – ViruMax Sep 30 '15 at 07:27
  • where you have defined dictionaryObject? – rishi Sep 30 '15 at 07:34
  • It is declared as an instance variable. – ViruMax Sep 30 '15 at 07:52
  • `signatures`, `timestamp, `dic`and `responseDataTemp`varialables are allocated but never released. – Nicolas Buquet Sep 30 '15 at 08:32
  • My project is using ARC thats why I have not released them manually, but as per instruments the main reason is responseJason function. – ViruMax Sep 30 '15 at 08:46
  • Same problem here. Any solution? – davidrelgr Nov 23 '15 at 18:23

0 Answers0