Code Monkey home page Code Monkey logo

rhaddressbook's Introduction

RHAddressBook

A Cocoa / Objective-C library for interfacing with the iOS AddressBook with added geocoding support.

  • All attributes on various objects are exposed as properties, allowing for simple Obj-C code. (No more dealing with CF methods etc )
  • Built in support for background Geocoding with an in-built persistent cache. (iOS5+ only)
  • vCard import and export for single and multiple people.
  • Access to all underlying ABRecordRefs & ABAddressBookRefs etc.
  • Maintains an underlying thread for each ab instance in-order to ensure thread safety.
  • Sends NSNotifications when ab has changed.
  • Geocoding is disabled by default. (See RH_AB_INCLUDE_GEOCODING)

Bonus Features

  • Unit Tests.
  • Basic Demo App.

Classes

  • RHAddressBook
  • RHSource - Representation of various address-book sources found on the iPhone
  • RHGroup
  • RHPerson - Represents a person in the addressbook.
  • RHMultiValue - Represents multiple key/value pairs. Used for RHPersons addresses etc.

Getting Started

Include RHAddressBook in your iOS project.

    #import <RHAddressBook/AddressBook.h>

Getting an instance of the addressbook.

    RHAddressBook *ab = [[[RHAddressBook alloc] init] autorelease];

Support for iOS6+ authorization

    //query current status, pre iOS6 always returns Authorized
    if ([RHAddressBook authorizationStatus] == RHAuthorizationStatusNotDetermined){
    
    	//request authorization
        [ab requestAuthorizationWithCompletion:^(bool granted, NSError *error) {
            [abViewController setAddressBook:ab];
        }];
    }

Registering for addressbook changes

    [[NSNotificationCenter defaultCenter]  addObserver:self selector:@selector(addressBookChanged:) name:RHAddressBookExternalChangeNotification object:nil];

Getting sources.

    NSArray *sources = [ab sources];
    RHSource *defaultSource = [ab defaultSource];

Getting a list of groups.

    NSArray *groups = [ab groups];
    long numberOfGroups = [ab numberOfGroups];
    NSArray *groupsInSource = [ab groupsInSource:defaultSource];
    RHGroup *lastGroup = [groups lastObject];

Getting a list of people.

    NSArray *allPeople = [ab people];
    long numberOfPeople = [ab numberOfPeople];
    NSArray *allPeopleSorted = [ab peopleOrderedByUsersPreference];
    NSArray *allFreds = [ab peopleWithName:@"Fred"];
    NSArray *allFredsInLastGroup = [lastGroup peopleWithName:@"Fred"];
    RHPerson *person = [allPeople lastObject];

Getting basic properties on on a person.

    NSString *department = [person department];
    UIImage *thumbnail = [person thumbnail];
    BOOL isCompany = [person isOrganization];

Setting basic properties on a person.

    person.name = @"Freddie";
    [person setImage:[UIImage imageNames:@"hahaha.jpg"]];
    person.kind = kABPersonKindOrganization;
    [person save];

Getting MultiValue properties on a person.

    RHMultiDictionaryValue *addressesMultiValue = [person addresses];
    NSString *firstAddressLabel = [RHPerson localizedLabel:[addressesMultiValue labelAtIndex]]; //eg Home
    NSDictionary *firstAddress = [addressesMultiValue valueAtIndex:0];

Setting MultiValue properties on a person.

    RHMultiStringValue *phoneMultiValue = [person phoneNumbers];
    RHMutableMultiStringValue *mutablePhoneMultiValue = [[phoneMultiValue mutableCopy] autorelease];
    if (! mutablePhoneMultiValue) mutablePhoneMultiValue = [[[RHMutableMultiStringValue alloc] initWithType:kABMultiStringPropertyType] autorelease];
    
    //RHPersonPhoneIPhoneLabel casts kABPersonPhoneIPhoneLabel to the correct toll free bridged type, see RHPersonLabels.h
    mutablePhoneMultiValue addValue:@"+14086655555" withLabel:RHPersonPhoneIPhoneLabel]; 
    person.phonenumbers = mutablePhoneMultiValue;
    [person save];

Creating a new person.

    RHPerson *newPerson = [[ab newPersonInDefaultSource] autorelease]; //added to ab
    RHPerson *newPerson2  = [[[RHPerson newPersonInSource:[ab defaultSource]] autorelease]; //not added to ab
    [ab addPerson:newPerson2];
    NSError* error = nil;
    if (![ab save:&error]) NSLog(@"error saving: %@", error);

Getting an RHPerson object for an ABRecordRef for editing. (note: RHPerson might not be associated with the same addressbook as the original ABRecordRef)

    ABRecordRef personRef = ...;
    RHPerson *person = [ab personForRecordRef:personRef];
    if(person){
        person.firstName = @"Paul";
        person.lastName = @"Frank";
        [person save];
    }

Presenting / editing an RHPerson instance in a ABPersonViewController.

    ABPersonViewController *personViewController = [[[ABPersonViewController alloc] init] autorelease];   

    //setup (tell the view controller to use our underlying address book instance, so our person object is directly updated on our behalf)
     [person.addressBook performAddressBookAction:^(ABAddressBookRef addressBookRef) {
        personViewController.addressBook =addressBookRef;
    } waitUntilDone:YES];

    personViewController.displayedPerson = person.recordRef;
    personViewController.allowsEditing = YES;

    [self.navigationController pushViewController:personViewController animated:YES];

Background geocoding

    if ([RHAddressBook isGeocodingSupported){
        [RHAddressBook setPreemptiveGeocodingEnabled:YES]; //class method
    }
    float progress = [_addressBook preemptiveGeocodingProgress]; // 0.0f - 1.0f

Geocoding results for a person.

    CLLocation *location = [person locationForAddressID:0];
    CLPlacemark *placemark = [person placemarkForAddressID:0];

Finding people within distance of a location.

    NSArray *inRangePeople = [ab peopleWithinDistance:5000 ofLocation:location];
    NSLog(@"people:%@", inRangePeople);

Saving. (all of the below are equivalent)

    BOOL changes = [ab hasUnsavedChanges];
    BOOL result = [ab save];
    BOOL result =[source save];
    BOOL result =[group save];
    BOOL result =[person save];

Reverting changes on objects. (reverts the entire addressbook instance, not just the object revert is called on.)

    [ab revert];
    [source revert];
    [group revert];
    [person revert];

Remember, save often in order to avoid painful save conflicts.

Installing

For instructions on how to get started using this static library see Using Static iOS Libraries at rheard.com.

Licence

Released under the Modified BSD License. (Attribution Required)

RHAddressBook

Copyright (c) 2011-2012 Richard Heard. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

iOS Version Support (Executive Summary: Supports iOS 4+, tested on iOS 4.0 - 7.1)

This Framework code runs and compiles on and has been tested all the way back to iOS 4.0.

Unit tests are in place that run on all versions between 4.0 and 7.1.

Various methods are not available when linking against older SDKs and will return nil when running on older os versions. eg. Geocoding is only supported on iOS 5+. You should always use the +[RHAddressBook isGeocodingAvailable] method to check whether geocoding is available before attempting to access geocode information. Methods will however, if available safely return nil / empty arrays.

rhaddressbook's People

Contributors

heardrwt avatar jeiting avatar ryanbertrand avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rhaddressbook's Issues

RHAddressBook::people - Duplicate entries for linked contacts

While playing around with RHAddressBook for an app i'm working on, I noticed that the people method in RHAddressBook.m will return duplicates if the contact exists in multiple sources. This seems to be a common issue, related to the underlying API.

Googling around, I came across this stackoverflow thread which seems to offer up a decent algorithm for a solution.

I think this would make a good addition to RHAddressBook. Something like this, but probably with better method names..

-(NSArray*)peopleWithoutLinkedDuplicates; // This would return an array of all users with 'linked duplicates' removed, returning the person from the default source for any duplicates (convenience method for below)

-(NSArray*)peopleWithoutLinkedDuplicatesShowingSource:(RHSource *)source; // This would return an array of all users with 'linked duplicates' removed, returning the person from the supplied source for any duplicates

I'd be happy to look at implementing this and sending a pull request if you'd like. Just let me know how you'd want the methods named, etc.

Better guidance for running with ARC?

I'll preface this ticket with the fact that I'm a new iOS dev (coming from python/frontend tools-land).

I've built the static library, ensuring to set the relevant flags:

screen shot 2013-05-16 at 5 25 17 pm

screen shot 2013-05-16 at 5 26 51 pm

Copied over the output and added it to my project:

screen shot 2013-05-16 at 5 27 38 pm

screen shot 2013-05-16 at 5 28 27 pm

I have no trouble importing the .h file:

#import "RHAddressBook/AddressBook.h"

However as soon as I try to instantiate an RHAddressBook instance, my app crashes at runtime:

RHAddressBook *ab = [[RHAddressBook alloc] init];

causes:

2013-05-16 17:30:52.755 Braid[6970:4003] -[RHAddressBookThreadMain threadMain:]:39 spawned thread: <NSThread: 0x777ad00>{name = RHAddressBookSharedServicesThread for 0x777abb0, num = 4} 
2013-05-16 17:30:52.755 Braid[6970:370f] -[RHAddressBookThreadMain threadMain:]:39 spawned thread: <NSThread: 0x777a990>{name = RHAddressBookInstanceThread for instance 0x777a870, num = 3} 
2013-05-16 17:30:52.755 Braid[6970:c07] -[NSThread rh_performBlock:]: unrecognized selector sent to instance 0x777ad00
2013-05-16 17:30:52.768 Braid[6970:c07] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSThread rh_performBlock:]: unrecognized selector sent to instance 0x777ad00'
*** First throw call stack:
(0x1bfc012 0x1518e7e 0x1c874bd 0x1bebbbc 0x1beb94e 0x40fc1 0x40c54 0x34c8c 0x33bd 0x53e1c7 0x53e232 0x53e4da 0x5558e5 0x5559cb 0x555c76 0x555d71 0x55689b 0x5569b9 0x556a45 0x65c20b 0x4ad2dd 0x152c6b0 0x247fc0 0x23c33c 0x247eaf 0x54c2bd 0x494b56 0x49366f 0x493589 0x4927e4 0x49261e 0x4933d9 0x4962d2 0x54099c 0x48d574 0x48d76f 0x48d905 0x496917 0x2c9f 0x45a157 0x45a747 0x45b94b 0x46ccb5 0x46dbeb 0x45f698 0x1b57df9 0x1b57ad0 0x1b71bf5 0x1b71962 0x1ba2bb6 0x1ba1f44 0x1ba1e1b 0x45b17a 0x45cffc 0x299d 0x28c5)
libc++abi.dylib: terminate called throwing an exception

Any pointers to help me figure out what I'm doing incorrectly? Google and I have been best buddies for a couple of hours now, to no avail.

Sources names

Hi

I cannot find a way to have the name of a source, as it would appear in Contacts app, after calling group button. I expected something like "iCloud" or "Exchange (work)" etc but I cannot find a way to get these names.

So how can I get those names ?
And what is the "name" property of RHSource used for ?

Thanks

Block execution until user grants authorisation to AddressBook

I'm trying to block program execution until the user grants access (or denies) access to the AddressBook, using a semaphore, however this seems to block the entire UI thread.
Using the code on http://stackoverflow.com/questions/12648244/programmatically-request-access-to-contacts-in-ios-6

If the semaphore is omitted, the execution continues (effectively loading no data), until the App is closed and reopened.

I have the following function:

- (RHAddressBook *) addressBook {
    @synchronized (self) {
        if (_ab == nil) {
            _ab = [[RHAddressBook alloc] init];


            if ([RHAddressBook authorizationStatus] == RHAuthorizationStatusNotDetermined) {
                //request authorization
                dispatch_semaphore_t sema = dispatch_semaphore_create(0);
                [_ab requestAuthorizationWithCompletion:^(bool granted, NSError *error) {                
                    dispatch_semaphore_signal(sema);
                }];
                dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
            }
        }
        return _ab;
    }
}

Crash when trying to save Instant Message multivalue

Here's the crash:

2013-01-08 01:17:51.775 XXXX[2851:50d7] -[__NSCFString count]: unrecognized selector sent to instance 0x1fb025c0
2013-01-08 01:17:51.776 XXXX[2851:50d7] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString count]: unrecognized selector sent to instance 0x1fb025c0'

Here's the associated code:

RHMultiStringValue *imMultiValue = [person instantMessageServices];
RHMutableMultiStringValue *mutableIMMultiValue = [imMultiValue mutableCopy];
if (! mutableIMMultiValue) mutableIMMultiValue = [[RHMutableMultiStringValue alloc] initWithType:kABMultiStringPropertyType];
[mutableIMMultiValue addValue: stringVar withLabel: RHPersonInstantMessageUsernameKey];
person.instantMessageServices = mutableIMMultiValue;
[person save];

I noticed that it behaves better by not crashing if I pass in a string literal as the value (the string I am using comes from a string decoded from JSON). However, the value is never added, only the label.

Crash when adding group

Hello,

I encountered a strange crash and I have no clue where to start investigating. I thought maybe you could offer some insight or maybe you encountered similar situations.
The code looks something like this:

NSError *err;
RHGroup *grp = [_addressBook newGroupInDefaultSource];
grp.name = groupName;
if (![_addressBook save: &err]) {
    errMsg = [NSString stringWithFormat:NSLocalizedString(@"Error adding group. Error: %@", nil), err.description];
    return nil;
}

return grp;

Sometimes this piece of code generates the following crash (relevant stack-traces below)

Thread 6 Crashed:
0   libsystem_kernel.dylib              0x320d6350 __pthread_kill + 8
1   libsystem_c.dylib                   0x354a1973 abort + 95
2   MyApp                              0x0012dd8b uncaught_exception_handler + 27
3   CoreFoundation                      0x3a3e057f __handleUncaughtException + 615
4   libobjc.A.dylib                     0x342cfa65 _objc_terminate() + 129
5   libc++abi.dylib                     0x385bf07b safe_handler_caller(void (*)()) + 79
6   libc++abi.dylib                     0x385bf114 std::terminate() + 20
7   libc++abi.dylib                     0x385c0599 __cxa_current_exception_type + 1
8   libobjc.A.dylib                     0x342cf9d1 objc_exception_rethrow + 13
9   CoreFoundation                      0x3a326f21 CFRunLoopRunSpecific + 457
10  CoreFoundation                      0x3a326d49 CFRunLoopRunInMode + 105
11  Foundation                          0x3513778f -[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 255
12  MyApp                              0x000ff91b -[RHAddressBookThreadMain threadMain:] + 283
13  Foundation                          0x351e467d __NSThread__main__ + 973
14  libsystem_c.dylib                   0x35447311 _pthread_start + 309


Thread 0:
0   libsystem_kernel.dylib              0x320d608c __psynch_cvwait + 24
1   libsystem_c.dylib                   0x35449f19 pthread_cond_wait + 41
2   Foundation                          0x35160ccf -[NSCondition wait] + 195
3   Foundation                          0x35137d6f -[NSObject(NSThreadPerformAdditions) performSelector:onThread:withObject:waitUntilDone:modes:] + 655
4   Foundation                          0x35161865 -[NSObject(NSThreadPerformAdditions) performSelector:onThread:withObject:waitUntilDone:] + 109
5   MyApp                              0x000fa8e9 -[NSThread(RHBlockAdditions) rh_performBlock:waitUntilDone:] + 157
6   MyApp                              0x000fa84b -[NSThread(RHBlockAdditions) rh_performBlock:] + 23
7   MyApp                              0x000f7b1b -[RHAddressBook save:] + 215
8   MyApp                              0x000dfba7 +[Global addGroupNamed:withError:] (Global.m:332)
9   MyApp                              0x000e4fdf -[GroupListController addGroupWithName:] (GroupListController.m:301)
10  MyApp                              0x000e4daf __36-[GroupListController onAddClicked:]_block_invoke_0 (GroupListController.m:267)
11  MyApp                              0x000e61ef -[ctzAlertView dismissWithClickedButtonIndex:animated:] (ctzAlertView.m:189)
12  UIKit                               0x335fd0a5 -[UIApplication sendAction:to:from:forEvent:] + 73
13  UIKit                               0x335fd057 -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 31
14  UIKit                               0x335fd035 -[UIControl sendAction:to:forEvent:] + 45
15  UIKit                               0x335fc8eb -[UIControl(Internal) _sendActionsForEvents:withEvent:] + 503
16  UIKit                               0x335fcde1 -[UIControl touchesEnded:withEvent:] + 489
17  UIKit                               0x335255f1 -[UIWindow _sendTouchesForEvent:] + 525
18  UIKit                               0x33512801 -[UIApplication sendEvent:] + 381
19  UIKit                               0x3351211b _UIApplicationHandleEvent + 6155
20  GraphicsServices                    0x386f55a3 _PurpleEventCallback + 591
21  GraphicsServices                    0x386f51d3 PurpleEventCallback + 35
22  CoreFoundation                      0x3a3b5173 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 35
23  CoreFoundation                      0x3a3b5117 __CFRunLoopDoSource1 + 139
24  CoreFoundation                      0x3a3b3f99 __CFRunLoopRun + 1385
25  CoreFoundation                      0x3a326ebd CFRunLoopRunSpecific + 357
26  CoreFoundation                      0x3a326d49 CFRunLoopRunInMode + 105
27  GraphicsServices                    0x386f42eb GSEventRunModal + 75
28  UIKit                               0x335662f9 UIApplicationMain + 1121
29  MyApp                              0x000b9315 main (main.m:19)

Thread 11 name:  Exception Backtrace
Thread 11:
0   CoreFoundation                      0x3a3e02a3 __exceptionPreprocess + 163
1   libobjc.A.dylib                     0x342cf97f objc_exception_throw + 31
2   CoreFoundation                      0x3a3e01c5 -[NSException initWithCoder:] + 1
3   CoreFoundation                      0x3a3579e5 -[__NSCFSet addObject:] + 157
4   Fliple                              0x000f7117 __26-[RHAddressBook addGroup:]_block_invoke_0 + 219
5   Fliple                              0x000faa25 -[NSThread(RHBlockAdditions) _rh_runBlock:] + 17
6   Foundation                          0x351e48ed __NSThreadPerformPerform + 461
7   CoreFoundation                      0x3a3b5683 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15
8   CoreFoundation                      0x3a3b4ee9 __CFRunLoopDoSources0 + 213
9   CoreFoundation                      0x3a3b3cb7 __CFRunLoopRun + 647
10  CoreFoundation                      0x3a326ebd CFRunLoopRunSpecific + 357
11  CoreFoundation                      0x3a326d49 CFRunLoopRunInMode + 105
12  Foundation                          0x3513778f -[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 255
13  Fliple                              0x000ff91b -[RHAddressBookThreadMain threadMain:] + 283
14  Foundation                          0x351e467d __NSThread__main__ + 973
15  libsystem_c.dylib                   0x35447311 _pthread_start + 309
16  libsystem_c.dylib                   0x354471d8 thread_start + 8

RHMultiStringValue

Sir, could you advise please? I'm trying to create instance of RHMultiStringValue but it doesn't work. I did everything as procedure. In the same controller RHAddressBook is working person retrieved but... What can be the cause?

Disable cache building as it takes a really really long ime and is not always necesary.

I have found that on very large datasets the cache takes a really long time to build.

This is obvious as the addressbook tries to geocode every address, this might be ok if the plan is to use the data later.

But in case this data is not relevant I have not found a way to disable this functionality.

The rest of the framework works really well and its a pleasure to use, thank you for building it!

I will try to get around sending a pull request once I get the basic architecture of the framework down.

Submit to CocoaPods

Hey there,

I've been using RHAddressBook for one of my projects and it's been working great! Would you mind submitting it to Cocoapods, or if you want, I'll go ahead and submit it for you.

Thanks

Question About CardDav accounts

I'm seeing when modifying contacts in a gmail account, that sometimes the contacts revert to the state they were in before the change (or in other cases a duplicate is added in the previous state). I assume this is not an issue with RHAddressbook, but I was wondering if you had seen this issue before.

Thanks,
John

Method for monitoring external address book changes

I've noticed that the external changes notification is fired multiple times even when my app is the one manipulating the contacts. This sort of creates an infinite loop situation as my app modifies the contacts when they are changed (which then triggers a notification). I've also noticed that it often gets called multiple times when I do manipulate the contacts manually outside the app. I only have one RHAddressbook instance that I create. Is this a known issue?

Thanks a lot,
John

Crash in [RHRecord performRecordAction:waitUntilDone:]_block_invoke_0

Hello,

I'm experiencing some unusual and inconsistent crashes when trying to access the thumbnail of an RHPerson object. I have about 6 crash reports, all with similar stack-traces.

I'm building against iOS SDK 6.0, the app is running on iOS 6.01 and is built with ARC, using the latest RHAddressBook code.

The stacktraces all look similar:

Exception Type:  SIGTRAP
Exception Codes: #0 at 0x39a5d68a
Crashed Thread:  4

Thread 0:
...
5   Fliple                              0x00063911 -[NSThread(RHBlockAdditions) rh_performBlock:waitUntilDone:] + 157
6   Fliple                              0x0005cc31 -[RHAddressBook performAddressBookAction:waitUntilDone:] + 121
7   Fliple                              0x00063b4b -[RHRecord performRecordAction:waitUntilDone:] + 127
8   Fliple                              0x00066e41 -[RHPerson imageWithFormat:] + 177
9   Fliple                              0x00066d77 -[RHPerson thumbnail] + 23
10  Fliple                              0x00022ac1 -[ctzDictionary tableView:cellForRowAtIndexPath:] (ctzDictionary.m:568) 
...

Thread 4 Crashed:
...
0   CoreFoundation                      0x39a5d68a _CFRelease + 18
1   Fliple                              0x00063b8d __46-[RHRecord performRecordAction:waitUntilDone:]_block_invoke_0 + 37
2   Fliple                              0x0005cc51 __56-[RHAddressBook performAddressBookAction:waitUntilDone:]_block_invoke_0 + 29
3   Fliple                              0x00063a49 -[NSThread(RHBlockAdditions) _rh_runBlock:] + 13
...

Most of the time the code runst just fine, except for some rare cases (that I couldn't reproduce so far), when it crashes.

My only suspicion is that the user has added/removed a contact source (such as Exchange/Facebook) and iOS is still adding/removing contacts in the background.
If this is the case, how could I protect my code against this kind of behavior?

Crash when externally changing authorization

Downloaded and crashed using RHAddressBookTester target on a REAL device.
Steps to reproduce:

  1. Launch Tester in device
  2. Goto Settings App, change the authorization for Tester app to use Address Book to off
  3. Crash on main()

Nothing in logs show any trace of what happened.

[RHPerson vCardRepresentationForPeople:] segfault

After receiving address book authorization a call to

[RHPerson vCardRepresentationForPeople:[addressBook people]]

results in a crash. Digging into the source it appears that while vCardRepresentationForPeople
expects an array of RHPerson objects, ABPersonCreateVCardRepresentationWithPeople expects a CFArray of ABRecordRef objects. Perhaps the ABRecordRef objects can be extracted from each RHPerson prior to the call to ABPersonCreateVCardRepresentationWithPeople.

Performance - rebuild cache

With a large number of contacts, calling

[[RHAddressBook alloc] init];

can take a few minutes and block the main thread. It seems to be blocking on the rebuildCache method. Wrapping in a GCD async dispatch fixes the problem, but it still takes a few minutes before the address book is accessible. Is there anything I can do to speed up the cache rebuild?

Problems with flags in new release

After updating to 1.1.0 problems with arc appeared. I do use a folder instead of packaging library to be able to make changes in source code. I have set the -all-load and -ObjC flags to "Other linker flags" and -fno-objc-arc to the files. Then tried different flags combinations but nothing worked for me.
Even tried moving from arc_autorelease to cfrelease and other similar solutions. Do you have any ideas on what should I do to use your lib with ARC?

RHAddressBookExternalChangeNotification fired multiple times

I believe this is not a bug in RHAddressBook, but I thought I may ask here. I'm registering to listen for RHAddressBookExternalChangeNotification. I modify a contact in the native Contacts app, go back to my app and receive the notification as expected.
But a few seconds later, without taking any action in my app, I get 3 or 4 more callbacks.

It's actually RHAddressBookExternalChangeCallback that gets called by the iOS SDK, so this callbacks come from iOS itself.

I'm checking what has changed by iterating over the contacts and comparing the "modified" property.
So I go back to the app, get a notification and this is logged:

2014-05-22 13:26:15.937 yyy[2584:3107] CONTACT XXXXXX modification date: 2014-05-22 12:26:11 +0000

A few seconds later, I get another notification and this is logged:
2014-05-22 13:26:23.763 yyy[2584:3107] CONTACT XXXXXX modification date: 2014-05-22 12:26:23 +0000

The same contact seems to have been modified between the notifications, but my app is not doing that at all. In fact, it never writes to the address book.

Any ideas?

-(NSArray *)people not thread-safe

Hit it during an in-development app, found a small amount of code that replicates the crash consistently on my iPhone 4S (iOS 6.1.2) and the simulator. Create an app with ARC, link against the necessary libs (AddressBook and CoreLocation).

ViewController.m:

#import "ViewController.h"
#import "RHAddressBook.h"

@interface ViewController ()

@property (nonatomic, strong) RHAddressBook *rhAddressBook;
@property (nonatomic, strong) NSOperationQueue *queue;

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    self.queue = [[NSOperationQueue alloc] init];
    self.rhAddressBook = [[RHAddressBook alloc] init];
    if ([RHAddressBook authorizationStatus] == RHAuthorizationStatusNotDetermined){

        //request authorization
        [self.rhAddressBook requestAuthorizationWithCompletion:^(bool granted, NSError *error) {
        }];
    }
}

- (IBAction)crashPressed:(id)sender {
    for(int i = 0; i < 100; i++) {
        [self.queue addOperationWithBlock:^{
            NSArray *people = self.rhAddressBook.people;
        }];
    }
}
@end

crashPressed is an outlet I connected to a button inside my ViewController nib. A single tap crashes, and from the location of the crash it seems like it's trying to send a message to a freed object. To verify I enabled zombie objects and then the program started crashing with the following log message:

*** -[RHPerson release]: message sent to deallocated instance 0x1d0c2510

I'll gladly send my zipped project if you wish. I didn't verify this using the provided test-case, but I would get the same crashes with and without ARC in RHAddressBook (my code always had ARC), and with and without USE_REF_MAP and USE_PERSON_ID_MAP. I didn't exhaustively try all the combinations of those parameters, but I tried more than half.

-[NSThread rh_performBlock:]: unrecognized selector sent to instance

Hello,
I tried to use RHAddressBook, but I'm going in circles with an issue that's already been reported.
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSThread rh_performBlock:]: unrecognized selector sent to instance 0x124991f0'
*** First throw call stack:
(
0 CoreFoundation 0x03a4c1e4 exceptionPreprocess + 180
1 libobjc.A.dylib 0x031fa8e5 objc_exception_throw + 44
2 CoreFoundation 0x03ae9243 -[NSObject(NSObject) doesNotRecognizeSelector:] + 275
3 CoreFoundation 0x03a3c50b __forwarding
+ 1019
4 CoreFoundation 0x03a3c0ee _CF_forwarding_prep_0 + 14
5 yy 0x000e6b19 -[RHAddressBookSharedServices init] + 537
6 yy 0x000e6833 +[RHAddressBookSharedServices sharedInstance] + 195

The library was created using -Objc -all_load, as suggested. But so far, no luck.
Any idea what I'm doing wrong ?
thanks in advance,
-M
screen shot 2014-04-08 at 15 49 33

Exception: -[NSThread rh_performBlock:]: unrecognized selector sent to instance

I just added RHAddressBook to my iOS project using CocoaPods. I imported the appropriate header file at the top of one of my ViewControllers:

#import <RHAddressBook/AddressBook.h>

Then, in viewDidLoad, I allocated and initialized an RHAddressBook instance:

RHAddressBook *ab = [[RHAddressBook alloc] init];

The app builds fine, but crashes on that line due to an uncaught exception. Relevant console output:

-[RHAddressBookThreadMain threadMain:]:39 spawned thread: <NSThread: 0xa624c50>{name = RHAddressBookInstanceThread for instance 0xa6265e0, num = 5} 
-[NSThread rh_performBlock:]: unrecognized selector sent to instance 0xa61aef0
-[RHAddressBookThreadMain threadMain:]:39 spawned thread: <NSThread: 0xa61aef0>{name = RHAddressBookSharedServicesThread for 0xa624dd0, num = 6} 
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSThread rh_performBlock:]: unrecognized selector sent to instance 0xa61aef0'

My project targets iOS 6 and is built with ARC enabled (though the RHAddressBook code itself is not built with ARC).

Stepping through the code, this exception is thrown the first time rh_performBlock is sent to an instance of NSThread. It seems like the RHBlockAdditions category is not being properly added to the NSThread class... Any ideas as to why this might be happening?

Hanging in rh_performBlock: with XCode 5.1 and iOS 7.1

I'm seeing my app hang frequently on this code ever since upgrading to XCode 5.1 and iOS 7.1. It happens when the app is installed on a device (more consistently for iPad Mini than iPhone 5s) but not in the simulator.

-(void)rh_performBlock:(VoidBlock)block waitUntilDone:(BOOL)wait{
//if current thread and wait (run directly)
if ([[NSThread currentThread] isEqual:self] && wait){
block(); return;
}
[self performSelector:@selector(_rh_runBlock:) onThread:self withObject:arc_autorelease([block copy]) waitUntilDone:wait];
}

image

RHPerson not being saved

In some cases I find that contacts are not being saved when using code like this:

RHPerson *person = [self getPersonWithNumber:number];
RHMutableMultiStringValue* mutablePhoneMultiValue = [[RHMutableMultiStringValue alloc] initWithType:kABMultiStringPropertyType];

[mutablePhoneMultiValue addValue:number withLabel:details];
person.phoneNumbers = mutablePhoneMultiValue;
person.firstName = @"John Smith";
[person save];

The code is hit but it is not reflected in the address book. Any suggestions? Could it be a threading issue?

Why RHAddressBookExternalChangeNotification is received when change the addressBook internally

I think this is a question more than an issue. Any one know about this?

In my app, I try to monitor the RHAddressBookExternalChangeNotification, and reload my contacts data feeds when received the notification.

But when I change the contact profile internally, and invoke the RHAddressBook save method, then I got 1~3 RHAddressBookExternalChangeNotification, I don't understand this.

Does RHAddressBookExternalChangeNotification means the address book is changed by external applications? Not the current app......

Thanks.

Disable geocoding support without needing to edit RHAddressBook.h

Hello,
Is there a way to disable geocoding support without needing to edit RHAddressBook.h?

I tried wrapping #define RH_AB_INCLUDE_GEOCODING 0 in an #ifndef and defining it in my prefix header, but the RHAddressBook library is built before my pch file is run, so I can't override it that way.

The reason I don't want to edit RHAddressBook.h is that I can't persist that change to the repo (and thus my other developers) unless I fork RHAddressBook.

Thanks,
Tommy

RHPerson::inSource confusing, source would be more logical

It took a while of searching around to figure out that inSource was the way to get the source. I think it would be more obvious if it was just source.

For backwards compatibility a convenience alias could be made of source calling back to inSource ?

Trouble extracting emails and phone numbers

Thank you for the wonderful library!

My issue:
I have a contacts application I'm trying to write, and I need to extract emails and phone numbers out of the device contacts. One consideration I've made is, if there are more than one HOME email or phone number (or any other type), I'll just grab the first one and not all of them.

Here is my code and I just can't seem to get the correct email / phone number. Am I doing this right?

NSArray *allContacts = [ab peopleOrderedByFirstName];

    for(RHPerson *p in allContacts){

        Person *person = [[Person alloc] init];

        NSString *firstName = [p firstName];
        NSString *lastName =  [p lastName];
        NSString *fullName = [p name];
        NSString *companyName = [p organization];

        if (firstName) {
            person.firstName = firstName;
        }
        if (lastName) {
            person.lastName = lastName;
        }
        if (fullName) {
            person.fullName = fullName;
        }
        if (companyName) {
            person.companyName = companyName;
        }

        //email
        RHMultiValue *emailsMultiValue = [p emails];

        if(emailsMultiValue != nil){
            // NSString *homeEmailLabel = [RHPerson localizedLabel:@"Home"]; //eg Home
            NSString *homeEmail = [emailsMultiValue valueAtIndex:[emailsMultiValue indexForIdentifier:0]];
            NSString *test = [emailsMultiValue multiValueRef];
            if (homeEmail) {
                person.homeEmail = homeEmail;
            }

            // NSString *homeEmailLabel = [RHPerson localizedLabel:[addressesMultiValue 1]]; //eg Work
            NSString *workEmail = [emailsMultiValue valueAtIndex:[emailsMultiValue indexForIdentifier:1]];
            if (workEmail) {
                person.workEmail = workEmail;
            }

        }

        //Phone
        RHMultiStringValue *phonesMultiValue = [p phoneNumbers];
        if (phonesMultiValue != nil) {
            // NSString *homePhoneLabel = [RHPerson localizedLabel:[phonesMultiValue 0]]; //eg Home
            NSString *homePhone = [phonesMultiValue valueAtIndex:0];
            if(homePhone){
                person.homePhone = homePhone;
            }

            NSString *workPhone = [phonesMultiValue valueAtIndex:1];
            if(workPhone){
                person.workPhone = workPhone;
            }

            NSString *cellPhone = [phonesMultiValue valueAtIndex:2];
            if(cellPhone){
                person.cellPhone = cellPhone;
            }
        }

Note:
This is working perfectly if the user has exactly one of each of the fields that I am trying to pull out for email and phone number...not if they don't have them or have too many...

Cannot compile in Xcode 4.5 GM when ARC is enabled

Multiple error occurred when compiling with Xcode 4.5 GM when ARC is enabled.

Here are some errors:

/Volumes/Data HD/Users/Kai/Downloads/heardrwt-RHAddressBook-62338d9/RHAddressBook/RHAddressBook.m:187:5: Cast of block pointer type 'void (^)(bool, NSError *__strong)' to C pointer type 'const void *' requires a bridged cast
/Volumes/Data HD/Users/Kai/Downloads/heardrwt-RHAddressBook-62338d9/RHAddressBook/RHAddressBook.m:187:5: Cast of C pointer type 'void *' to block pointer type 'typeof (completion)' (aka 'void (^__strong)(bool, NSError *__strong)') requires a bridged cast
/Volumes/Data HD/Users/Kai/Downloads/heardrwt-RHAddressBook-62338d9/RHAddressBook/RHAddressBook.m:196:37: Cast of C pointer type 'CFErrorRef' (aka 'struct __CFError *') to Objective-C pointer type 'NSError *' requires a bridged cast
/Volumes/Data HD/Users/Kai/Downloads/heardrwt-RHAddressBook-62338d9/RHAddressBook/RHAddressBook.m:198:17: Cast of block pointer type 'void (^)(bool, NSError *__strong)' to C pointer type 'const void *' requires a bridged cast
/Volumes/Data HD/Users/Kai/Downloads/heardrwt-RHAddressBook-62338d9/RHAddressBook/RHAddressBook.m:211:9: Cast of block pointer type 'void (^)(bool, NSError *__strong)' to C pointer type 'const void *' requires a bridged cast

Specify Public Headers in Podspec?

According to the CocoaPods documentation:

If you do not explicitly set the list of public header files, all headers of source_files will be made public.
s.public_header_files = 'Classes/*/.h'

In your XCode project, you specify 6 private headers:

RHAddressBookSharedServices.h
RHAddressBookGeoResult.h
NSThread+RHBlockAdditions.h
RHAddressBookThreadMain.h
RHAddressBook_Private.h
RHAddressBook/RHRecord_Private.h

Unless I'm missing something, it seems like the CocoaPods podspec should specify your public headers so that the above 6 headers are treated as private when CocoaPods builds RHAddressBook into its static library?

newPersonInDefaultSource retains emails and phone numbers

I am working on a App which Syncs new/existing contacts with the default Address book. To avoid duplicates I am searching for person in the AddressBook and if I get any results I simply update the Person. Furthermore, to avoid duplication of phone numbers and email addresses within the Person I do the following,

//Set phone number if exists
if(user.phone){
RHMultiStringValue *phoneMultiValue = [person phoneNumbers];
RHMutableMultiStringValue *mutablePhoneMultiValue = [phoneMultiValue mutableCopy];
if (! mutablePhoneMultiValue) mutablePhoneMultiValue = [[RHMutableMultiStringValue alloc] initWithType:kABMultiStringPropertyType];

    //Avoid Duplicates
    NSInteger phoneIndex = [mutablePhoneMultiValue firstIndexOfValue:user.phone];

    if(phoneIndex == -1){
        [mutablePhoneMultiValue addValue:user.phone withLabel:RHPersonPhoneIPhoneLabel];
        person.phoneNumbers = mutablePhoneMultiValue;
    }
}

//Set email if exists
if( user.email){
    RHMultiStringValue *emailMultiValue = [person emails];

    RHMutableMultiStringValue *mutableEmailMultiValue = [emailMultiValue mutableCopy];
    if (! mutableEmailMultiValue) mutableEmailMultiValue = [[RHMutableMultiStringValue alloc] initWithType:kABMultiStringPropertyType];

    //Avoid duplicates
    NSInteger emailIndex = [mutableEmailMultiValue firstIndexOfValue:user.email];
    if(emailIndex == -1){
        [mutableEmailMultiValue addValue:user.email withLabel:RHWorkLabel];
        person.emails = mutableEmailMultiValue;
    }
}

This works great for users that are already in the AddressBook but when I created a new user with,
[RHPerson newPersonInSource:[self.addressBook defaultSource]];

Things get funky!!
[person emails] and [person phoneNumbers] returns an array with pre-populated values from random contacts in the AddressBook even though a new RHPerson was created.

I did manage to workaround it forcing initialization on setting emails and phoneNumbers when a new Person is created as follows,

person.emails = [[RHMultiStringValue alloc] init];
person.phoneNumbers = [[RHMultiStringValue alloc] init];

This fixed my issue but would like to dig deep as to why this is happening.

Performance: Option to use RHAddressBook without multi-threading support

RHAddressBook API is great, but performance lags far behind direct ABAddressBook access. Simple example running on iPhone 5s

    NSDate *date;
    date = [NSDate date];
    NSTimeInterval taken;
    ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(nil, NULL);
    CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeopleInSourceWithSortOrdering(addressBook, NULL, ABPersonGetSortOrdering());
    taken = [[NSDate date] timeIntervalSinceDate:date];

    for (id person in (__bridge NSArray *)allPeople) {
        // Get the name of the contact
        NSString *firstName = (__bridge_transfer NSString*)ABRecordCopyValue((__bridge ABRecordRef)(person), kABPersonFirstNameProperty);
        NSString *lastName = (__bridge_transfer NSString*)ABRecordCopyValue((__bridge ABRecordRef)(person), kABPersonLastNameProperty);
        id email = (__bridge_transfer NSString*)ABRecordCopyValue((__bridge ABRecordRef)(person), kABPersonEmailProperty);
        id phone = (__bridge_transfer NSString*)ABRecordCopyValue((__bridge ABRecordRef)(person), kABPersonPhoneProperty);
    }
    NSLog(@"abaddressbook took %f seconds %ld", taken, CFArrayGetCount(allPeople));

    date = [NSDate date];
    RHAddressBook *book = [[RHAddressBook alloc] init];
    NSArray *people = [book peopleOrderedByUsersPreference];
    for (RHPerson *person in people) {
        person.firstName;
        person.lastName;
        person.phoneNumbers;
        person.emails;
    }
    taken = [[NSDate date] timeIntervalSinceDate:date];
    NSLog(@"rhaddressbook took %f seconds %ld", taken, (long)people.count);

And logs

2013-10-20 12:25:46.806 [813:60b] abaddressbook took 0.057833 seconds 779
2013-10-20 12:25:47.260 [813:60b] rhaddressbook took 0.452621 seconds 779

An order of magnitude slower :( There ought to be a way to access the RHAddressBook in a high performance manner without all the overhead of waiting for secondary thread synchronously

Slow cache build due to geocode object creation

Hi,

I found out that the cache building operation takes a very long time. I have 800+ contacts on iCloud and this step takes more than 5sec at app launch. It is not that bad, but still can be an issue.

I ran instruments and discovered that 70%+ of this time is spent on -[RHAddressBookGeoResult initWithPersonID:addressID] -> -[RHAddressBookGeoResult associatedAddressDictionary] -> ABAddressBookCreateWithOptions() or ABAddressBookCreate() .

By skipping the if(addesses) part in -[RHAddressBookSharedServices rebuildCache] I was able to speed things up to a quick 300ms startup.

If I understand well the goal of this if it is to get coordinate of every addresses, so I definitely need it for my app, but can't we prevent this time consuming operation by sharing an addressBookRef instance ?

Stan

iOS6: adressbook access not granted problem

If the access to contact is not activated in settings:
we have this error:
[RHAddressBookSharedServices init]:125 Error: Failed to create RHAddressBookSharedServices instance. Underlying ABAddressBookCreateWithOptions() failed with error: Error Domain=ABAddressBookErrorDomain Code=1 "The operation couldn’t be completed. (ABAddressBookErrorDomain error 1.)"

and then, the application is blocked in that code (see the '---->' mark):
-(void)deregisterForAddressBookChanges{
if (![[NSThread currentThread] isEqual:_addressBookThread]){
----> [self performSelector:_cmd onThread:_addressBookThread withObject:nil waitUntilDone:YES];
return;
}
....

This because _addressBookThread is Nil.

to solve this problem, I have test if we are not in that situation, then the code will be

-(void)deregisterForAddressBookChanges{
if(_addressBookThread != nil) {
if (![[NSThread currentThread] isEqual:_addressBookThread]){
[self performSelector:_cmd onThread:_addressBookThread withObject:nil waitUntilDone:YES];
return;
}
} else {
return;
}

If you have other solution, I am taker...

Thanks!

Add convenience method "name" to RHPerson

Hi Richard,

it would be great to add a convenience method "name" to RHPerson.
It is great for debugging.

-(NSString *)name {
NSMutableString *string = [NSMutableString string];

if (self.firstName || self.lastName)
{
    if (self.prefix) [string appendFormat:@"%@ ", self.prefix];
    if (self.firstName) [string appendFormat:@"%@ ", self.firstName];
    if (self.nickname) [string appendFormat:@"\"%@\" ", self.nickname];
    if (self.lastName) [string appendFormat:@"%@", self.lastName];

    if (self.suffix && string.length)
        [string appendFormat:@", %@ ", self.suffix];
    else
        [string appendFormat:@" "];
}

if (self.organization) [string appendString:self.organization];
return [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];

}

This was taken from Erica Sadun' s ABContact.m file.

Deprecations need fixing

RHAddressBook uses these two deprecated methods. They need to be replaced.

ABAddressBookCreate() and ABPersonGetCompositeNameFormat()

Control geolocation inclusion/exclusion at runtime

Hi Richard,
I am reopening my previous issue slightly different, since by using Cocoapods you cannot exclude geolocation by having a define in the projects .pch but a change in the RHAddressBook.h file is required.
So if the project is updated one needs to change it again.
It would be more flexible to add geolocation at runtime instead.

Crash when Addressbook changes.

My App is crashing when the addressbook is changed. How do I debug this?
AddressBook
ABAddressBookHasUnsavedChanges + 79
1
AddressBook
ABLogAPIUsage + 26
2
RHAddressBook.m line 1055
34-[RHAddressBook hasUnsavedChanges]_block_invoke
3
libdispatch.dylib
_dispatch_client_callout + 22
4
libdispatch.dylib
_dispatch_barrier_sync_f_slow + 230
5
RHAddressBook.m line 1054
-[RHAddressBook hasUnsavedChanges]
6
RHAddressBook.m line 1069
-[RHAddressBook addressBookExternallyChanged:]
7
CoreFoundation
__CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER
+ 12
8
CoreFoundation
_CFXNotificationPost + 1720
9
Foundation
-[NSNotificationCenter postNotificationName:object:userInfo:] + 72
10
Foundation
-[NSNotificationCenter postNotificationName:object:] + 30
11 libdispatch.dylib
_dispatch_call_block_and_release + 10
19 UIKit
UIApplicationMain + 1136
20
main.m line 16
main

Impressive feature set but slow

I was impressed by the feature set provided by the library.
My old library (ABContactHelper by Erica Sadun) was replaced in half an hour.
But to my surprise, it was more than 2-3 times slower.

Can you take look at this?

How to set RHMultiDictionaryValue?

this doesn't work, unfortunately:

[socialProfiles addValue:@"myKey" withLabel:RHPersonSocialProfileServiceKey];
[socialProfiles addValue:@"myValue" withLabel:RHPersonSocialProfileUsernameKey]

I'm looking for a replacement for

    ABMultiValueRef social = ABMultiValueCreateMutable(kABMultiDictionaryPropertyType);
    {
        CFStringRef valueCFString = (__bridge CFStringRef) value;
        CFStringRef keys[] = {
                kABPersonSocialProfileServiceKey,
                kABPersonSocialProfileUsernameKey
        }, values[] = {
                CFSTR("myKey"),
                CFSTR("myValue")
        };

        ABMultiValueAddValueAndLabel(social, CFDictionaryCreate(kCFAllocatorDefault, (void *) keys, (void *) values, 3, NULL, NULL), NULL, NULL);
    }

    CFErrorRef error;
    ABRecordSetValue(rhPerson.recordRef, kABPersonSocialProfileProperty, social, &error);

    CFRelease(social);

thanks a LOT!

[RHAddressBook people] does not retain objects in the array

I am getting this error [RHPerson phoneNumbers]: message sent to deallocated instance intermittently.
It all happens in a single function similar to this:

NSArray *people = [addressBook people];
for (RHPerson *person in people)
{
   RHMultiValue *phoneNumbers = [person phoneNumbers];
}

It seems to me that the records are not retained properly.

I did spend time trying to identify the problem, but no luck.

BTW, I am using ARC and there is no internal/external change to the address book in my test.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.