views:

56

answers:

2

Hey All,

I have problem with the way I treat the memory management in iphone..please please help me..I am running out of ideas..I tried to play with the below method but it started leaks when I am trying to allocate the strings for the objects (for example allocation for sid,first_name etc)..I can't figure out how to do..and this is the method where I will get all the contacts from the service and insert it into the database..It consumes more memory which I figured out by running allocations instrument on iphone and my app on iphone crashes..please please help me guys..What is the better solution for it..I think my app consumes more memory but not sure where to look into it..I can post any code if this is not clear..thanks a lot!!!

- (void) get_entry_listHandler: (id) value{

    NSString *salutation,*sugar_id,*first_name,*last_name,*title1,*department,*phone_home,*phone_mobile,*phone_work,*phone_other,*phone_fax,*assistant,*assistant_phone,*primary_address_street,*primary_address_city,*primary_address_state,*primary_address_postalcode,*custom;
    NSString *primary_address_country,*alt_address_street,*alt_address_city,*alt_address_state,*alt_address_postalcode,*alt_address_country,*date_entered,*date_modified,*deleted,*do_not_call,*birthdate,*lead_source,*description,*email1,*email2,*account_name,*account_id,*id1;

    // Handle errors
    if([value isKindOfClass:[NSError class]]) {
        NSLog(@"%@", value);
        return;
    }

    // Handle faults
    if([value isKindOfClass:[SoapFault class]]) {
        NSLog(@"%@", value);
        return;
    }               

    // Do something with the SCRMget_entry_list_result* result
    SCRMget_entry_list_result* result = (SCRMget_entry_list_result*)value;
    //NSLog(@"get_entry_list returned the value: %@", result);
    //NSLog(@"%@", result.entry_list);
    NSLog(@"%@", result.error);

    SCRMsugarsoap* service = [[SCRMsugarsoap alloc] initWithUrl:serverURL];
    SCRMentry_value* entry;
    for(NSString * myStr in result.entry_list) {
        entry = (SCRMentry_value*)myStr;
        //NSLog(@"1st %@",entry.name_value_list);
        //NSLog(@"1st %@",entry.id);
        //NSLog(@"1st %@",entry.module_name);

        for(NSString * myStr1 in entry.name_value_list) {

            SCRMname_value* value1 = (SCRMname_value*)myStr1;
            if ([value1.name isEqualToString:@"id"])
                sugar_id = [[NSString alloc] initWithFormat: @"%@",value1.value];
            else if ([value1.name isEqualToString:@"salutation"])
                salutation = [[NSString alloc] initWithFormat: @"%@",value1.value];
            else if ([value1.name isEqualToString:@"first_name"])
                first_name = [[NSString alloc] initWithFormat: @"%@",value1.value];
            else if ([value1.name isEqualToString:@"last_name"])
                last_name = [[NSString alloc] initWithFormat: @"%@",value1.value];
            else if ([value1.name isEqualToString:@"title"])
                title1 = [[NSString alloc] initWithFormat: @"%@",value1.value];
            else if ([value1.name isEqualToString:@"department"])
                department = [[NSString alloc] initWithFormat: @"%@",value1.value];
            else if ([value1.name isEqualToString:@"phone_home"])
                phone_home = [[NSString alloc] initWithFormat: @"%@",value1.value];
            else if ([value1.name isEqualToString:@"phone_mobile"])
                phone_mobile = [[NSString alloc] initWithFormat: @"%@",value1.value];
            else if ([value1.name isEqualToString:@"phone_work"])
                phone_work = [[NSString alloc] initWithFormat: @"%@",value1.value];
            else if ([value1.name isEqualToString:@"phone_other"])
                phone_other = [[NSString alloc] initWithFormat: @"%@",value1.value];
            else if ([value1.name isEqualToString:@"phone_fax"])
                phone_fax = [[NSString alloc] initWithFormat: @"%@",value1.value];
            else if ([value1.name isEqualToString:@"assistant"])
                assistant = [[NSString alloc] initWithFormat: @"%@",value1.value];
            else if ([value1.name isEqualToString:@"assistant_phone"])
                assistant_phone = [[NSString alloc] initWithFormat: @"%@",value1.value];
            else if ([value1.name isEqualToString:@"primary_address_street"])
                primary_address_street = [[NSString alloc] initWithFormat: @"%@",value1.value];
            else if ([value1.name isEqualToString:@"primary_address_city"])
                primary_address_city = [[NSString alloc] initWithFormat: @"%@",value1.value];
            else if ([value1.name isEqualToString:@"primary_address_state"])
                primary_address_state = [[NSString alloc] initWithFormat: @"%@",value1.value];
            else if ([value1.name isEqualToString:@"primary_address_postalcode"])
                primary_address_postalcode = [[NSString alloc] initWithFormat: @"%@",value1.value];
            else if ([value1.name isEqualToString:@"primary_address_country"])
                primary_address_country = [[NSString alloc] initWithFormat: @"%@",value1.value];
            else if ([value1.name isEqualToString:@"alt_address_street"])
                alt_address_street = [[NSString alloc] initWithFormat: @"%@",value1.value];
            else if ([value1.name isEqualToString:@"alt_address_city"])
                alt_address_city = [[NSString alloc] initWithFormat: @"%@",value1.value];
            else if ([value1.name isEqualToString:@"alt_address_state"])
                alt_address_state = [[NSString alloc] initWithFormat: @"%@",value1.value];
            else if ([value1.name isEqualToString:@"alt_address_postalcode"])
                alt_address_postalcode = [[NSString alloc] initWithFormat: @"%@",value1.value];
            else if ([value1.name isEqualToString:@"alt_address_country"])
                alt_address_country = [[NSString alloc] initWithFormat: @"%@",value1.value];
            else if ([value1.name isEqualToString:@"date_entered"])
                date_entered = [[NSString alloc] initWithFormat: @"%@",value1.value];
            else if ([value1.name isEqualToString:@"date_modified"])
                date_modified = [[NSString alloc] initWithFormat: @"%@",value1.value];
            else if ([value1.name isEqualToString:@"deleted"])
                deleted = [[NSString alloc] initWithFormat: @"%@",value1.value];
            else if ([value1.name isEqualToString:@"do_not_call"])
                do_not_call = [[NSString alloc] initWithFormat: @"%@",value1.value];
            else if ([value1.name isEqualToString:@"birthdate"])
                birthdate = [[NSString alloc] initWithFormat: @"%@",value1.value];
            else if ([value1.name isEqualToString:@"lead_source"])
                lead_source = [[NSString alloc] initWithFormat: @"%@",value1.value];
            else if ([value1.name isEqualToString:@"description"])
                description = [[NSString alloc] initWithFormat: @"%@",value1.value];
            else if ([value1.name isEqualToString:@"email1"])
                email1 = [[NSString alloc] initWithFormat: @"%@",value1.value];
            else if ([value1.name isEqualToString:@"email2"])
                email2 = [[NSString alloc] initWithFormat: @"%@",value1.value];
            else if ([value1.name isEqualToString:@"account_name"])
                account_name = [[NSString alloc] initWithFormat: @"%@",value1.value];


            else if ([value1.name isEqualToString:@"account_id"])
                account_id = [[NSString alloc] initWithFormat: @"%@",value1.value];
            else
                custom = [[NSString alloc] initWithFormat: @"%@",value1.value];
            }

        NSDateFormatter *df = [[NSDateFormatter alloc] init];
        [df setFormatterBehavior:NSDateFormatterBehavior10_4];
        [df setDateFormat:@"yyy-MM-dd HH:mm:ss"];
        NSDate *date_moded = [df dateFromString:date_modified];
        NSDate *lastSync = [df dateFromString:lastSyncTime];
        NSDate *date_enter = [df dateFromString:date_entered];
        [df release];

        if ([[date_moded laterDate:lastSync]isEqualToDate:date_moded] && lastSyncTime != nil && [date_enter isEqualToDate:date_moded])
            id1 = [[NSString alloc]initWithFormat:@"%d",primaryKeyCount];
        else if ([[date_moded laterDate:lastSync]isEqualToDate:date_moded] && lastSyncTime != nil )
            id1 = [db getPrimaryKey:sugar_id];
        else
            id1 = [[NSString alloc]initWithFormat:@"%d",primaryKeyCount];

        [db insertRecordIntoTableNamed: @"Contacts" withField1: @"id" field1Value: id1 andField2: @"sugar_id" field2Value: sugar_id 
                         andField3: @"salutation" field3Value: salutation andField4: @"first_name" field4Value: first_name 
                         andField5: @"last_name" field5Value: last_name andField6: @"title" field6Value: title1 
                         andField7: @"department" field7Value: department andField8: @"phone_home" field8Value: phone_home
                         andField9: @"phone_mobile" field9Value: phone_mobile andField10: @"phone_work" field10Value: phone_work 
                        andField11: @"phone_other" field11Value: phone_other andField12: @"phone_fax" field12Value: phone_fax
                        andField13: @"assistant" field13Value: assistant andField14: @"assistant_phone" field14Value: assistant_phone 
                        andField15: @"primary_address_street" field15Value: primary_address_street andField16: @"primary_address_city" field16Value: primary_address_city 
                        andField17: @"primary_address_state" field17Value: primary_address_state andField18: @"primary_address_postalcode" field18Value: primary_address_postalcode 
                        andField19: @"primary_address_country" field19Value: primary_address_country andField20: @"alt_address_street" field20Value: alt_address_street
                        andField21: @"alt_address_city" field21Value: alt_address_city andField22: @"alt_address_state" field22Value: alt_address_state
                        andField23: @"alt_address_postalcode" field23Value: alt_address_postalcode andField24: @"alt_address_country" field24Value: alt_address_country
                        andField25: @"date_entered" field25Value: date_entered andField26: @"date_modified" field26Value: date_modified 
                        andField27: @"deleted" field27Value: deleted andField28: @"do_not_call" field28Value: do_not_call 
                        andField29: @"birthdate" field29Value: birthdate andField30: @"lead_source" field30Value: lead_source 
                        andField31: @"description" field31Value: description andField32: @"email1" field32Value: email1
                        andField33: @"email2" field33Value: email2 andField34: @"account_name" field34Value: account_name 
                        andField35: @"account_id" field35Value: account_id andField36: @"custom" field36Value: custom];
        primaryKeyCount++;
        currentCount++;
        //NSLog(@"%D",i);
    }
    [salutation release];
    [sugar_id release];
    [first_name release];
    [last_name release];
    [title1 release];
    [department release];
    [phone_home release];
    [phone_mobile release];
    [phone_work release];
    [phone_fax release];
    [phone_other release];
    [assistant release];
    [assistant_phone release];
    [primary_address_street release];
    [primary_address_city release];
    [primary_address_state release];
    [primary_address_postalcode release];
    [primary_address_country release];
    [alt_address_street release];
    [alt_address_city release];
    [alt_address_state release];
    [alt_address_postalcode release];
    [alt_address_country release];
    [custom release];
    [date_entered release];
    [deleted release];
    [do_not_call release];
    [birthdate release];
    [lead_source release];
    [description release];
    [email1 release];
    [email2 release];
    [account_name release];
    [account_id release];

    float expected = (float) contactEntries;
    float gotSoFar = (float) currentCount;


    syncViewController.progressView.progress = ((float)((gotSoFar - 1) / (expected + 1)));
    syncViewController.progressLabel.text=[NSString stringWithFormat:@"Syncing %d Contacts",contactEntries]; 

    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    integer = [NSNumber numberWithInt:primaryKeyCount];
    [defaults setObject:integer forKey:@"primaryKeyCount"];
    [defaults synchronize];

    moduleViewController.db = db;
    int a = result.next_offset;
    int b = contactEntries;
    while (result.result_count == 20 /*&& result.next_offset < contactEntries*/) {
        if ( lastSyncTime == nil) {
            [service get_entry_list:self action:@selector(get_entry_listHandler:) session:sessionId module_name: @"Contacts" query: @"" order_by: @"" offset: result.next_offset select_fields: [[[SCRMselect_fields alloc] init]autorelease] max_results: contactEntries deleted: 0];
            [service release];
            return;
            //break;
        }
        else {
            [service get_entry_list:self action:@selector(get_entry_listHandler:) session:sessionId module_name: @"Contacts" query: finalQuery order_by: @"" offset: result.next_offset select_fields: [[[SCRMselect_fields alloc] init]autorelease] max_results: contactEntries deleted: 0];
            [service release];
            return;
            //break;
        }
    }

    if (a >= b ) {
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
        [settingsViewController.navigationController pushViewController:moduleViewController animated:YES];
        NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
        [defaults setBool:NO forKey:@"reset"];
        [defaults synchronize];
        [finalQuery release];
    }
    /*else if (a >= b && syncing == YES) {
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
        [moduleViewController reload];
    }*/

    [service release];
    [id1 release];

}

EDIT:

I got rid of all the leaks but can any one please tell me how to check the object allocations instrument in iphone..Please see the below screenshot..My app gets crashed once it loads all the 4200 contacts and the contacts are never displayed on the table view..What might be the problem..I make sure that the place from which my contacts is saved to the database is leak free..In the below screenshot what exactly should I look for..is it the total allocation or living..please let me know guys..I am totally exhausted..thanks a lot for your time.. alt text

+3  A: 

You should put the [string release]; lines inside the for(NSString * myStr in result.entry_list) loop. Each time you call alloc, there must be a corresponding release call.

A better way to do it is to use [NSString stringWithFormat:] instead of [[NSString alloc] initWithFormat:] so that you don't need to release them manually.

My app gets crashed once it loads all the 4200 contacts and the contacts are never displayed on the table viewnever displayed on the table view

4200 contacts make your loop "large and tight". As suggested by taskinoor, you can create and drain an NSAutoreleasePool for every a few loops to reduce memory foot print. For example:

int counter = 0;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
for (...) {
    if (++counter == 100) {
        counter = 0;
        [pool release];
        pool = [[NSAutoreleasePool alloc] init];
    }
  //busy working...
}
[pool release];

Your app may also be terminated by iOS if it takes too long to respond to system events. This mechanism is know as watchdog timeout. In this case, you'll find the exception code 0x8badf00d in the crash report. You may want to break the work into smaller batches or use a secondary thread so that the main thread won't be busy for too long.

Arrix
you really should not edit your answer after checking the other answer(s). Or at least specify that you have copied from other answer. This is a cowardice behavior.
taskinoor
I edited the screenshot..please guide me friends..
racharambola
@taskinoor: You really think the idea of using a convenience constructor was such an original concept of yours that you downvote answers that don't credit you with it? Downvoting good answers because you're worried they might take votes from yours is more cowardly than incorporating a good idea into your answer. I'm not going to downvote you because your answer is also correct, but please try not to be so aggressive towards other users. The point is to help the person with the question, not to "beat" other users.
Chuck
When I try to run the app through xcode it outputs the following message on log:Program received signal: “0”.Data Formatters temporarily unavailable, will re-try after a 'continue'. (Unknown error loading shared library "/Developer/usr/lib/libXcodeDebuggerSupport.dylib")
racharambola
@chuck, im not trying to beat the others. to me, it just seems insulting and non-respect to others if i edit my answer after seeing the response of others and dont acknowledge that. personally i wont never do that. why should i add something in my answer that is already said by someone else? is it going to help the people more? instead of adding the content in my answer, i think it will be more respectful if i just make a note "see the other answer" or something similar. i think u got my point.
taskinoor
@taskinoor Sorry but I did not copy from any place other than the documentation. When I edited my answer, stackoverflow was showing it as the only one (I didn't refresh the page after posting). I'm glad that our answers are consistent. I've up voted your answer because it's more detailed and mentions the use of a dedicated autorelease pool. Good points! I hope you don't find it "insulting" or "non-respect" any more. Sorry for being off topic, I just think its necessary to clarify.
Arrix
@Arrix, thanks for ur comment. actually after making my 1st comment i was waiting for ur reply. well, i agree that i was too aggressive, may be i was in bad mood in last night. i think i must say sorry too /*im not a rude person :-)*/. sorry for the whole misunderstanding. btw, i cant cancel my negative vote unless u edit ur answer. i guess its a feature of SO :-(
taskinoor
Thanks Arrix for the detailed answer..If I use autorelease pools will it get rid of watch dog timeout bug..and where should I write the autorelease pool statements..should it be inside this for(NSString * myStr1 in entry.name_value_list) loop before allocating the strings..sorry it may sound too silly but I am writing my first app..thanks for your time..
racharambola
+2  A: 

This is a long code and may be I'm wrong. But my guess is this .

for(NSString * myStr in result.entry_list) {
    // lots of alloc
}
// releases in this point

Now if you have more than one entry in result.entry_list (which I guess you have), aren't you leaking the strings? Say you have alloced str in 1st pass and in the 2nd pass during next alloc you are leaking this. Got my point?

If this is the problem, then you should move the release calls inside the loop.

Another solution is that it seems that you don't need the strings outside this scope. So why don't you use autorealse method to create it?

str = [NSString stringWithFormat:@"what_you_need"];

You don't need to release them now. Though in this case you should consider creating your own autorelease pool as the amount of data might be huge.

taskinoor
thanks for the reply..I will try it and let you know..
racharambola
I edited the screenshot..please guide me friends.
racharambola