iOSAppDev
iOSAppDev

Reputation: 2783

Reduce time to perform big operation on iphone app

When I launch an app, I need to retrieve all contacts from Address Book & store it in array to display it in table view. I wrote this code in viewDidAppear method. While contacts are retrieving from Address Book , I am showing activity indicator. I have around 1100 contacts in my address book. For this it took 14 seconds to retrieve data & store it in array. Its not acceptable time. So I need to optimize this & reduce time to max 2 to 3 seconds.

I need all contacts because when my app launches , I need to search for contacts so I need all the data available in my array.

How can I reduce this timing ? If you need more information just let me know. Any kind of help is highly appreciated. Thanks.

UPDATE 1 : My code

    - (NSMutableArray*)getAddressBookData {

    self.tempArray = [[NSMutableArray alloc]init];
    addressBook = ABAddressBookCreate();
    APP_DELGATE.people = (NSArray*)ABAddressBookCopyArrayOfAllPeople(addressBook);
    peopleCount = [APP_DELGATE.people count];

    for (int i=0; i<peopleCount; i++) {

        ABRecordRef record = [APP_DELGATE.people objectAtIndex:i];

        NSNumber *recordId = [NSNumber numberWithInteger:ABRecordGetRecordID(record)];
        NSLog(@"record id is %@",recordId);

        // Get fname, lname, company
        NSString *fnm = (NSString *)ABRecordCopyValue(record, kABPersonFirstNameProperty) ;
        NSString *lnm = (NSString *)ABRecordCopyValue(record, kABPersonLastNameProperty) ;
        NSString *comp = (NSString*)ABRecordCopyValue(record,kABPersonOrganizationProperty);

        // Get Ph no
        ABMultiValueRef phoneNumberProperty = ABRecordCopyValue(record, kABPersonPhoneProperty);
        NSArray* phoneNumbers = [self getPhoneNoWithoutSymbols:(NSArray*)ABMultiValueCopyArrayOfAllValues(phoneNumberProperty)];
        NSString *strPhoneNos = [self getStringRepresentaionFromArray:phoneNumbers];
        NSLog(@"strPhoneNos => %@",strPhoneNos);

        // Get emails
        ABMultiValueRef emailProperty = ABRecordCopyValue(record, kABPersonEmailProperty);
        NSArray* emails = (NSArray*)ABMultiValueCopyArrayOfAllValues(emailProperty);
        NSString *strEmails = [self getStringRepresentaionFromArray:emails];
        NSLog(@"strEmails => %@",strEmails);

        // Get URL
        ABMultiValueRef urlProperty = ABRecordCopyValue(record, kABPersonURLProperty);
        NSArray* urls = (NSArray*)ABMultiValueCopyArrayOfAllValues(urlProperty);
        NSString *strURLs = [self getStringRepresentaionFromArray:urls];
        NSLog(@"strURLs => %@",strURLs);

        // Get Address
        ABMultiValueRef address=ABRecordCopyValue(record, kABPersonAddressProperty);
        CFDictionaryRef dic=nil;
        NSMutableArray *addressArray = [[NSMutableArray alloc]init];
        for (int index=0; index<ABMultiValueGetCount(address); index++) {

            dic=ABMultiValueCopyValueAtIndex(address, index);
            NSString* labelName=(NSString*)ABMultiValueCopyLabelAtIndex(address, index);

            if (labelName) {

                NSString *street =(NSString*) CFDictionaryGetValue(dic, kABPersonAddressStreetKey);
                NSString  *city= (NSString*)CFDictionaryGetValue(dic, kABPersonAddressCityKey) ;
                NSString  *state= CFDictionaryGetValue(dic, kABPersonAddressStateKey);
                NSString *country=CFDictionaryGetValue(dic, kABPersonAddressCountryKey);
                NSString *zipcode=CFDictionaryGetValue(dic, kABPersonAddressZIPKey);

                NSString *addressDetails=@"";
                if (street) {
                    addressDetails=[NSString stringWithFormat:@"%@ ",street];
                }
                if (city) {
                    addressDetails=[NSString stringWithFormat:@"%@ %@ ",addressDetails,city];
                }
                if (state) {
                    addressDetails=[NSString stringWithFormat:@"%@ %@ ",addressDetails,state];
                }                    
                if (country) {
                    addressDetails=[NSString stringWithFormat:@"%@ %@ ",addressDetails,country];
                }
                if (zipcode) {
                    addressDetails=[NSString stringWithFormat:@"%@ %@ ",addressDetails,zipcode];
                }

                [addressArray addObject:addressDetails];

            }

        }

        NSString *strAddress = [self getStringRepresentaionFromArray:addressArray];
        NSLog(@"strAddress => %@",strAddress);

        // Get Notes
        NSString *noteString=(NSString *)ABRecordCopyValue(record, kABPersonNoteProperty);

        // Get Birthdate
        NSDate *birthDate=(NSDate*)ABRecordCopyValue(record, kABPersonBirthdayProperty) ;
        NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
        [formatter setDateFormat:@"MMMM dd yyyy"];
        NSString *birthdateString = [formatter stringFromDate:birthDate];
        [formatter release];

        // Get user image
        UIImage *image = nil;
        if( ABPersonHasImageData( record ) ) {
            NSData *imageData = (NSData*)ABPersonCopyImageData(record);
            image = [UIImage imageWithData:imageData];
            [imageData release];
        }

        // Create User object & add it to array
        User *user = [[User alloc]initUserWithUniqID:recordId.intValue FirstName:fnm lastName:lnm company:comp phoneNumbers:strPhoneNos emails:strEmails  urls:strURLs address:strAddress notes:noteString dob:birthdateString userImage:image];

        [self.tempArray addObject:user];
        [user release];
    }

    self.tempArray = [NSMutableArray arrayWithArray:[self.tempArray sortedArrayUsingSelector:@selector(compare:)]];

    APP_DELGATE.allUsersArray = self.tempArray;
    return tempArray;
}



-(NSMutableArray*)getPhoneNoWithoutSymbols:(NSArray*)array {

    self.phNoArray = [[NSMutableArray alloc]init];
    for (NSString *str in array) {
        [self.phNoArray addObject:[self getPhNo:str]];
    }
    return self.phNoArray;
}

-(NSString*)getPhNo:(NSString*)str {

    NSString *str0 = [str stringByReplacingOccurrencesOfString:@" " withString:@""];
    NSString *str1 = [str0 stringByReplacingOccurrencesOfString:@"(" withString:@""];
    NSString *str2 = [str1 stringByReplacingOccurrencesOfString:@")" withString:@""];
    NSString *str3 = [str2 stringByReplacingOccurrencesOfString:@"-" withString:@""];
    return str3;
}

-(NSString*)getStringRepresentaionFromArray:(NSArray*)array {

    return [array componentsJoinedByString:DELIMITER_SYMBOL];
}

Upvotes: 0

Views: 407

Answers (3)

Manish Agrawal
Manish Agrawal

Reputation: 11026

When your app first install fetch all the contacts and save in coredate/plist file when next time app opens then show the contacts from the storage which is very fast as compare to fetching contacts from iPhone database. Now the problem how to update contacts which newly added, so for every contact there is property called "kABPersonModificationDateProperty" and "kABPersonCreationDateProperty" ,use this to find only updated contacts and add in the storage. Hope this helps.

Upvotes: 0

Parth Bhatt
Parth Bhatt

Reputation: 19469

Firstly, try some general approaches to reduce time by using more optimized code and less repetition of code and also through less use of loops or may be only iterate loops only till the data is obtained. Also you can check whether your code is properly distributed as far as the Time Profiling is concerned.

Secondly, we feel that time required is more because user is shown an Activity Indicator till 14 seconds. If you don't show it and don't block the User Interface till data is getting copied into your array, then user may feel that it is more smooth So here is how you can do that:

You can use NSThread to allow the application to launch while you retrieve all your data from the AddressBook and Store it in your array.

You can use

[NSThread detachNewThreadSelector:@selector(fetchAddressContacts:) withObject:nil];

For more information you can refer to detachNewThreadSelector: from NSThread

So basically in AppDelegate you need to code as following in AppDelegate.m

-(void)applicationDidFinishLaunching:(UIApplication *)application {
       [NSThread detachNewThreadSelector:@selector(fetchAddressContacts) withObject:nil];
}

-(void)fetchAddressContacts {
       //Do your stuff to copy your contacts from address book to array
       // Once you finish this task you can trigger an NSNotification which could be caught on some other viewController or implement a delegate to transfer data to a viewController and proper actions can be executed once the data is loaded.
}

Let me know if you need more help.

Hope this helps you.

Upvotes: 1

serb
serb

Reputation: 318

  1. Perform your contacts retrieval method diagnostics and identify what calls are causing the bottleneck here.
  2. Share your code and describe the bottlenecks

Any operation taking serious amount of time should be performed in a thread. In this case, I'd gather the data on first startup only and store them internally. You can refresh the primary data anytime later on demand (refresh button?) otherwise work with the internally stored "clone" of the contacts rather than calling any time-consuming operation on every app's start.

BTW: Be careful about the address book contacts these days :-)

Upvotes: 0

Related Questions