Accessing Address Book in iPhone SDK?

Discussion in 'iPhone/iPad Programming' started by jhershauer, Mar 7, 2008.

  1. macrumors member

    Joined:
    Feb 3, 2003
    Location:
    Gilbert, AZ
    #1
    Hi,
    I've created a simple list application, starting out with a custom datasource class that simply returns a hard-wired list of data. With that working, I'm now attempting to alter my datasource class to pull data from the address book. I've added a reference to AddressBook/ABAddressBook.h and created an ABAddressBookRef variable. The application compiles fine with that, and I'm able to get Code Sense into the ABAddressBook API. However, if I attempt to initialize my ABAddressBookRef variable by calling ABAddressBookCreate(), I get a link error like this:

    "_ABAddressBookCreate", referenced from:
    -[TestTableDataSource init] in TestTableDataSource.o
    symbol(s) not found
    collect2: id returned 1 exit status

    I'm new to this environment, so there may be something obvious I'm missing here in terms of setting this up. Has anybody successfully initialized/accessed the Address Book API with the iPhone SDK yet? Any quick samples of how to get the ball rolling with that API?

    Thanks,
    Jeff
     
  2. Moderator emeritus

    kainjow

    Joined:
    Jun 15, 2000
    #2
    Did you link in the entire framework?
     
  3. thread starter macrumors member

    Joined:
    Feb 3, 2003
    Location:
    Gilbert, AZ
    #3
    Wow...quick response! I was just coming back to answer myself. No, I hadn't linked in that framework. I was just poking around and noticed the "Linked Frameworks" node in the Groups and Files pane. All is well now.

    Thanks!

    Jeff
     
  4. thread starter macrumors member

    Joined:
    Feb 3, 2003
    Location:
    Gilbert, AZ
    #4
    Follow-up question

    OK, I've got a follow-up question that's more of a beginner Objective-C question:

    I wanted to create a couple of class-level variables ("ivars" I suppose they're called). One would be a pointer to the AddressBook itself, and the other would point to the array of all people in the Address Book (NSArray *). This was so I wouldn't have to keep re-getting these things in the other methods of my class.

    I was looking for the equivalent of a "constructor" in Objective-C and found the -init() method, so I overrode that as follows:

    Code:
    -(id)init
    {
    	self = [super init];
    	addressBook = <SDKMehtodToGetAddressBook>();
    	allPeople = (NSArray *)<SDKMethodToGetArrayOfPeople>(addressBook);
    	return self;
    }
    This didn't work. When I got into my other methods, addressBook and allPeople were always nil. I got around this by turning addressBook and allPeople into properties, and implementing getters like this:


    Code:
    - (<SDKTypeThatReferencesAnAddressBook>)_getAddressBook {
    	if (nil == addressBook)
    	{
    		addressBook = <SDKMethodToReturnAnAddressBook>();
    	}
    	return addressBook;
    }
    - (NSArray *)_getAllPeople {
    	if (nil == allPeople)
    	{
    		allPeople = (NSArray *)<SDKMethodToGetArrayOfPeople>(self.addressBook);
    	}
    	return allPeople;
    }

    This works fine, and my application is happily running in the simulator, returning a list of people from the address book. However, I'm curious as to why the assignments to the allPeople and addressBook variables didn't "stick" when I tried to do it through the init method. I've done some google searching, and that seems like it's supposed to be the appropriate place to initialize ivars for the class. Any insight would be appreciated.


    Here's the interface for my class:

    Code:
    #import <SDK UI Kit>
    #import <SDK Address Book>
    
    
    @interface TestTableDataSource : NSObject <UITableViewDataSource, UITableViewDelegate> {
    <SDKAddressBookReferenceType> addressBook;
    NSArray *allPeople;
    }
    
    @property (getter=_getAddressBook,assign) <SDKTypeThatReferencesAnAddressBook> addressBook;
    @property (getter=_getAllPeople,assign) NSArray *allPeople;
    - (NSString *)stringValueForRow:(NSInteger)row;
    
    @end
    Thanks,
    Jeff

    [Edit]: Hmm...I see other references to NDA, and although this thing is publicly available now, I know I agreed to something (didn't actually read it) when I downloaded the SDK, so I've gone back and attempted to kind of obfuscate the code so as not to give any SDK "secrets" away. :)
     
  5. Moderator emeritus

    kainjow

    Joined:
    Jun 15, 2000
    #5
    Your init method may not be getting called. You can NSLog() it to see if it is.

    How is your class being created?
     
  6. thread starter macrumors member

    Joined:
    Feb 3, 2003
    Location:
    Gilbert, AZ
    #6
    Doh! I feel like an idiot. You're right...the init wasn't being called. I could have sworn I put a breakpoint in my init method to make sure the variables were getting set, but I must not have (taking in a lot of new stuff all at once, and probably getting a bit discombobulated).

    Your tip was enough to point me to my problem. I was creating my class instance like this:

    Code:
        //Set up data source
        testDs = [TestTableDataSource alloc];
    Now I'm creating it like this, and it's working:

    Code:
    	
        //Set up data source
        testDs = [[TestTableDataSource alloc] init];
    I was assuming that simply doing an alloc on the class was the equivalent of doing a New in C#, and thought my init (which I was thinking of as a constructor) would automatically be called.

    At least I learned how to create custom property accessors in the process. :)

    Thanks again!

    Jeff
     
  7. macrumors newbie

    Joined:
    Jul 2, 2007
    #7
    Hey, I'm trying to do something similar. How did you find usages for the ABAddressBookRef class? I looked at the library ref on the developer center, but it had no example code and nothing about how to create the instance. I feel like I must be missing a large amount of reference documentation somewhere.

    Thanks
     
  8. macrumors newbie

    Joined:
    Mar 11, 2008
    #8
    All of the reference documentation is available in the research assistant, and apple has squirreled away tons of example code inside of the documentation bundle. Go to Help, and then "Show research assistant".

    Search in the SDK and you should be set.
     
  9. macrumors newbie

    Joined:
    Mar 11, 2008
    #9
    I have a similar problem to yours, but it seems that the compiler is not finding any of the header files. I have errors like:

    Code:
    /Users/jna/Documents/Iphone App Dev/WhatHappened/Classes/../RootViewController.m:194: error: 'ABPerson' undeclared (first use in this function)
    /Users/jna/Documents/Iphone App Dev/WhatHappened/Classes/../RootViewController.m:194: error: 'aPerson' undeclared (first use in this function)
    /Users/jna/Documents/Iphone App Dev/WhatHappened/Classes/../RootViewController.m:194: error: 'ABAddressBook' undeclared (first use in this function)
    /Users/jna/Documents/Iphone App Dev/WhatHappened/Classes/../RootViewController.m:195: error: 'ABMutableMultiValue' undeclared (first use in this function)
    /Users/jna/Documents/Iphone App Dev/WhatHappened/Classes/../RootViewController.m:195: error: 'anAddressList' undeclared (first use in this function)
    /Users/jna/Documents/Iphone App Dev/WhatHappened/Classes/../RootViewController.m:196: error: 'kABAddressProperty' undeclared (first use in this function)
    /Users/jna/Documents/Iphone App Dev/WhatHappened/Classes/../RootViewController.m:198: warning: unused variable 'primaryIndex'
    
    and I have certainly put the framework in both the 'link binary with libraries' part of my target, as well as in the 'linked framework' part. What gives?

    Why can't it see the header files?!
     
  10. macrumors newbie

    Joined:
    Jul 2, 2007
    #10
    Thanks for the info.

    I am still having an issue though. I show the Research Assistant, but mo matter what I click on, even non-iPhone SDK classes, I see nothing in the window. Is there something I'm missing? I tried just putting the cursor over the class name in the code, and also highlighting the name.

    Thanks
     
  11. Moderator emeritus

    kainjow

    Joined:
    Jun 15, 2000
    #11
    Did you #import <AddressBook/AddressBook.h> ?
     
  12. macrumors newbie

    Joined:
    Jul 2, 2007
    #12
    So I've finally managed to get the Research Assistant working, but now I have a new question. This may be a dumb question but, how did you manage to get a list of all the records in the address book? In looking at the doc and the AddressBookh file, I see no functions for just getting a or all of the records.

    Thanks!
     
  13. thread starter macrumors member

    Joined:
    Feb 3, 2003
    Location:
    Gilbert, AZ
    #13
    For that, you'll want to import the ABPerson header file and take a look at the available functions there. I believe it's also documented. There's an ABAddressBookCopyArrayOfAllPeople function that will get you all of the records. You'll need your address book reference as a parameter for the ABPerson functions.

    Jeff
     
  14. macrumors newbie

    Joined:
    Jul 2, 2007
    #14
    Awesome, thanks so much!

    One more question to anybody who can answer. Am I missing something here, or are all the AddressBook libraries standard C libraries? I'm finding myself relying on all of these C functions that are passed object references and parameters, it seems to defeat the idea of using Objective C as an OO language for the SDK. Are there some sort of OC wrappers for all this functionality? Or are some of the APIs just standard C, no if an or buts?

    Thanks,
    Nick
     
  15. macrumors newbie

    Joined:
    Mar 11, 2008
    #15
    Ahh, it was getting the headers but I was used to addressbook in cocoa and accessing it the wrong way.

    The iPhone SDK is a bit different, so, to open the address book and get the contacts, it looks something like this:

    Code:
    // open the default address book. 
    	ABAddressBookRef m_addressbook = ABAddressBookCreate();
        if (!m_addressbook) {
            NSLog(@"opening address book");
        }
    	
    	// can be cast to NSArray, toll-free
    	CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(m_addressbook);
    	CFIndex nPeople = ABAddressBookGetPersonCount(m_addressbook);
    
    	// CFStrings can be cast to NSString!
    
    	for (int i=0;i < nPeople;i++) { 
    		ABRecordRef ref = CFArrayGetValueAtIndex(allPeople,i);
    		... do something with ABRecordRef...
    	}
    
    	[region release];
    
     
  16. macrumors newbie

    Joined:
    Mar 11, 2008
    #16
    Importing <AddressBook/AddressBook.h> all of the other header files for you. You shouldn't import ABPerson.h directly.
     
  17. macrumors newbie

    Joined:
    Jul 2, 2007
    #17
    Reassuring to see that, it's almost exactly what I have. Thanks for the tip on the casting though, I didn't realize those foundations classes could be cast into NS classes that easily.

    Do you know how I could go about getting which indexes are for which Record properties? It seems like there should be a list somewhere, but I could not find one.
    Thanks
     
  18. macrumors regular

    Joined:
    Mar 13, 2008
    #18
    i think youre talking about how to get the values in the database fields...? something like this?
    PHP:
    NSString *contactFirstLast = [NSString stringWithFormat:@"%@,%@"
      
    ABRecordCopyValue(refkABPersonFirstNameProperty), 
      
    ABRecordCopyValue(refkABPersonLastNameProperty)
    ];
    the kABPersonBlahBlahProperty constants (or enums, i forgot what they are) are decribed in the ABPerson documentation pages. it's a little more difficult to get a hold of the multivalues, like addresses and phone numbers, ive got something working if you need it, but i feel it's not as nice as it could be.
     
  19. Moderator emeritus

    kainjow

    Joined:
    Jun 15, 2000
    #19
    Any values used from ABRecordCopyValue() need to be released when done, so that code above is leaking memory, and if you use that in a loop with every contact, that'd be a lot of memory to leak.

    It should probably be something like this:

    Code:
    CFStringRef firstName = ABRecordCopyValue(ref, kABPersonFirstNameProperty);
    CFStringRef lastName = ABRecordCopyValue(ref, kABPersonLastNameProperty);
    NSString *contactFirstLast = [NSString stringWithFormat:@"%@,%@",
        firstName, lastName];
    CFRelease(firstName);
    CFRelease(lastName);
     
  20. macrumors regular

    Joined:
    Mar 13, 2008
    #20
    thanks for pointing that out. i should have said that in my previous post - i only started with obj-c a couple of days ago ;)

    now anyone has any idea how to get the own phone's phone number?... on the iPhone it shows up on top of the "all contacts" list, but i couldnt find it anywhere in the address book database.
     
  21. macrumors 6502

    gifford

    Joined:
    Jun 11, 2007
    Location:
    Miserable England
    #21
    I have been trundling through the adressbook iphone framework all day looking for ways to receive "missed call" events, are an array of missed calls, or any info to do with missed calls.

    Has anyone spotted any info on this anywhere?
     
  22. macrumors newbie

    Joined:
    Mar 11, 2008
    #22
    I really don't have my head completely around references and what needs to be released and what doesn't yet.

    I don't understand how you can copy something into a reference, and then release it, and still be able to use it. Got a reference for this that I can read?
     
  23. macrumors newbie

    Joined:
    Mar 11, 2008
    #23
    I don't think you're going to get that from the address book.

    There's no section of the SDK that I can find to get to call, calendar, or voice mail data, so I guess that's not available just yet. Maybe there's an NSDictionary someplace with this?
     
  24. macrumors 6502

    gifford

    Joined:
    Jun 11, 2007
    Location:
    Miserable England
    #24
    I was told by one of the guy's from Apple that address book was where to look. So I kept on looking, and looking, and looking, and now I have given up.

    I will have to wait I suppose, the application I want it for has already been put off for 3 years in anticipation of the iphone (and lack of patience to learn any other inevitably doomed mobile platform) so whats another couple of years gona make!
     
  25. Moderator emeritus

    kainjow

    Joined:
    Jun 15, 2000
    #25

Share This Page