Pages Menu
Categories Menu

Posted by on Jan 28, 2009 in Code, Mobile |

iPhone Programming: Adding a Contact to the iPhone Address Book

 

Adding a contact to the iPhone’s address book isn’t horribly complicated, but it’s not the most straightforward process in the world, either, because the documentation leaves a bit to be desired. There is an Address Book Programming Guide published by Apple, but at 28 pages, it feels a bit bloated when you’re just trying to quickly figure out a simple process like this, and somewhat ironically, the “Creating a New Person” section is less than a page, and doesn’t go into much detail. The XCode documentation is helpful, but it still takes some effort to put all the pieces together, so this is basically just a walk-through of the process of creating a new contact, and adding some common fields to it.

To create a new record, we start out by creating a CFErrorRef variable that will hold any errors that get generated throughout the rest of the process. In my experience, most errors here tend to generate exceptions anyway, but there’s an error parameter, so we may as well use it. Anyway, here’s the line:

        CFErrorRef error = NULL; 

We then create our reference to the iPhone Address Book with a call to ABAddressBookCreate():

        ABAddressBookRef iPhoneAddressBook = ABAddressBookCreate();

And then we create a new person record:

        ABRecordRef newPerson = ABPersonCreate();
At this point, we haven’t saved anything to the address book yet, but we can start adding data to the person record. To do this, we use ABRecordSetValue, but some fields need to be formatted differently from others. For some, like first name and last name, we can just pass in a string:

        ABRecordSetValue(newPerson, kABPersonFirstNameProperty, @”John”, &error);
ABRecordSetValue(newPerson, kABPersonLastNameProperty, @”Doe”, &error);

kABPersonFirstNameProperty and kABPersonLastNameProperty are constants defined by Apple that specify which fields you’re saving. They’re listed in the XCode documentation under Personal Information Properties in the ABPerson Reference document. We can also set some other fields in this manner, such as company and title:

        ABRecordSetValue(newPerson, kABPersonOrganizationProperty, @”Model Metrics”, &error);
ABRecordSetValue(newPerson, kABPersonJobTitleProperty, @”Senior Slacker”, &error);

Where it gets a bit trickier is when we want to set our phone, email, or address properties, because these fields use ABMutableMultiValueRef rather than strings to store the data, and the specific data types of the values vary a bit depending on which one we’re talking about. For phone, we would do something like this:
        ABMutableMultiValueRef multiPhone = ABMultiValueCreateMutable(kABMultiStringPropertyType);
ABMultiValueAddValueAndLabel(multiPhone, @”1-555-555-5555″, kABPersonPhoneMainLabel, NULL);
ABMultiValueAddValueAndLabel(multiPhone, @”1-123-456-7890″, kABPersonPhoneMobileLabel, NULL);
ABMultiValueAddValueAndLabel(multiPhone, @”1-987-654-3210″, kABOtherLabel, NULL);
ABRecordSetValue(newPerson, kABPersonPhoneProperty, multiPhone,nil);
CFRelease(multiPhone);

The first two phone types (kABPersonPhoneMainLabel and kABPersonPhoneMobileLabel) are listed as Phone Number Properties in the ABPerson Reference, along with kABPersonPhoneHomeFAXLabel, kABPersonPhoneWorkFAXLabel, and kABPersonPhonePagerLabel. Despite the fact that the two fax numbers and the pager number seem fairly useless (you can’t send a fax from your phone, and who has a pager anymore?) but there’s nothing listed there for Other, or Work Phone or anything like that. That’s where the Generic Property labels come into play:

      kABWorkLabel;
kABHomeLabel;
kABOtherLabel;

Those will file the phone numbers as Work, Home, and Other, respectively. After adding the values to the ABMutableMultiValueRef, we need to call ABRecordSetValue, only this time instead of passing a string in for the third parameter, we pass in multiPhone. Then be sure to free up the memory with CFRelease.

Adding email addresses to the record is pretty similar to adding phone numbers, where we create an ABMutableMultiValueRef of strings:

        ABMutableMultiValueRef multiEmail = ABMultiValueCreateMutable(kABMultiStringPropertyType);
ABMultiValueAddValueAndLabel(multiEmail, @”johndoe@modelmetrics.com”, kABWorkLabel, NULL);
ABRecordSetValue(newPerson, kABPersonEmailProperty, multiEmail, &error);
CFRelease(multiEmail);

Where it gets a little different is when we go to set the street address values. While we do still use an ABMutableMultiValueRef, we won’t be using kABMultiStringPropertyType. To set the street address, we use kABMultiDictionaryPropertyType instead, so we have to create an NSMutableDictionary, and the method calls end up being a bit different:

        ABMutableMultiValueRef multiAddress = ABMultiValueCreateMutable(kABMultiDictionaryPropertyType);

NSMutableDictionary *addressDictionary = [[NSMutableDictionary alloc] init];

            [addressDictionary setObject:@”750 North Orleans Street, Ste 601″ forKey:(NSString *) kABPersonAddressStreetKey];
[addressDictionary setObject:@”Chicago” forKey:(NSString *)kABPersonAddressCityKey];
[addressDictionary setObject:@”IL” forKey:(NSString *)kABPersonAddressStateKey];
[addressDictionary setObject:@”60654″ forKey:(NSString *)kABPersonAddressZIPKey];

          ABMultiValueAddValueAndLabel(multiAddress, addressDictionary, kABWorkLabel, NULL);
ABRecordSetValue(newPerson, kABPersonAddressProperty, multiAddress,&error);
CFRelease(multiAddress);

kABWorkLabel means that we’re setting this as the contact’s work address. And to add it to the contact record, we call ABRecordSetValue as before, releasing the memory afterward.

The last step is to add the new record to the address book, and save it back to the device:

        ABAddressBookAddRecord(iPhoneAddressBook, newPerson, &error);
ABAddressBookSave(iPhoneAddressBook, &error);

And then we can check for any errors:

        if (error != NULL)
{

                  NSLog(@”Danger Will Robinson! Danger!”);

        }

 

So that concludes this introduction to creating new records in the address book.

Tom

Facebooktwitterredditpinterestlinkedinmail Read More

Posted by on Jan 23, 2009 in Code, Mobile |

Lessons for the Beginning iPhone Developer

Getting started with iPhone development can be an intense process. If you’re not coming from the world of OSX development, you’re probably more familiar with the myriad languages that look more like C++ than Smalltalk, and you have a lot of new syntactical things to learn, with square-brackets in abundance. It can be easy to focus completely on learning the syntax of Objective-C, and forget that the iPhone is a device with more severe limits on resources than computers, and that you will ultimately have to get your app approved by Apple before you can distribute it, so you need to follow their guidelines to the letter.

Following are some lessons indented for developers who are well versed in any number of other programming languages, but who are coming to the iPhone for the first time.

Memory Management

This one is huge, and easy to underestimate. Don’t develop your entire application and then decide to check to see if you have any memory problems. The iPhone has about 128 MB of volatile memory on board, and the virtual memory model does not include swap space. This means that, even though your iPhone has 8GB or 16GB of Flash storage, memory that your application allocates will not be swapped out to the disk to free up system memory. Since over-releasing objects will crash an application in often difficult to understand ways, it can be tempting to never release objects. However, the system monitors memory usage, and shuts down any application that takes up too much memory. This is the cause of a great many application crashes on the iPhone. You can use around 30 MB safely. Get closer to 40 or 50, and the system will very likely shut your app down with an exit status of 101.

Technically speaking, the system monitors total memory usage in order to maintain continuity of critical applications, such as the phone system, the audio system, and other systems that run constantly on the phone. When total memory usage climbs high enough that the functionality of these systems is put in jeopardy, the application currently on top of the stack will be shut down. This does mean that it is possible for one of these background processes to be using too much memory, causing your app to be shut down. Shutting down the phone and restarting usually takes care of these sorts of conditions.

Definitely read and understand the Memory Management Programming Guide for Cocoa, it’s one of the most important documents to read.

Generally, the Memory Management guide can be summed up by saying that you must release any object that you create with alloc, new, or copy, or one that you have specifically retained with retain.

Human Interface Guidelines

Read and understand the Apple Human Interface Guidelines. Apple calls this document “required reading” for a reason. They’re not being allegorical. Failure to follow the guidelines has resulted in many apps being rejected from the app store. You can always resubmit, of course, but resubmitting means you’ll have to wait for your app to be approved again.

Understanding the Review Process

Before you can distribute your app on the App Store, you’ll have to submit the app to Apple for review. This can take anywhere from a few days to…unfortunately…a few months. Most apps will get some sort of response from Apple within a week. These responses fall into three categories:

  1. Approved: Hooray! Your app will appear in the App Store shortly.
  2. Rejected: Unless your app has been deemed inappropriate for the app store, you will be given a list of items to fix. Fix them and resubmit for approval.
  3. Unexpected Additional Time to Review: This is bad. iPhone developer forums are full of stories of apps that have gotten this feedback, and have been stuck in the queue for months to follow. It may be a good idea to resubmit your app at this point and hope for another reviewer. I haven’t found any definitive answers on what the best course of action is when this happens.

Exception Breakpoints

By default, exceptions are not very easy to trace in XCode. This is a pain because it makes it impossible to debug application crashes. Luckily, the solution is pretty simple. Adding a global breakpoint for “obj_exception_throw” and “–[NSException raise]” will cause XCode to break on exceptions, allowing the stack trace to be viewed. Global breakpoints can be added in XCode under Run => Show => Breakpoints.

“malloc_error_break” can be used to obtain information on a malloc error.

Zombies!

Over-releasing objects can cause difficult to track down problems, usually resulting in an EXC_BAD_ACCESS exception. Setting the NSZombieEnabled environment variable will dynamically change the class of deallocated objects to _NSZombie rather than actually freeing the memory. This does mean that memory is never freed, so obviously, this isn’t something to be left on all the time, but it can come in handy when trying to track down over-releases and premature releases. NSZombieEnabled is set by editing the Active Executable, and adding an Environment Variable named “NSZombieEnabled” with a value of “YES”.

GDB Console Commands

Debugging in XCode is frustrating until you realize the power of GDB in the console. Set a breakpoint in your code, and you can learn all sorts of things with these commands:

  • print (unsigned int)[someObject retainCount]
    • display the retain count of an object
  • print (unsigned int)[[someObject size] retain]
    • Show the size of an object. The retain is necessary to keep the object from being released here.
  • po someObject
    • display information about an object. In the case of an NSString, the string will be printed.
  • po [someView subviews]
    • Print an array of subviews of a view. 

 

Facebooktwitterredditpinterestlinkedinmail Read More