操作系統通訊錄實現添加與讀取聯系人


引言:這是我之前寫在博客園的一篇記錄筆記,因個人比較喜歡簡書的書寫環境與閱讀氣氛,所以統一整理到這里,做個備忘吧O(∩_∩)O哈哈~!


蘋果提供了訪問系統通訊錄的框架,以便開發者對系統通訊錄進行操作。想要訪問通訊錄,需要添加AddressBookUI.framework和AddressBook.framework兩個框架,添加的地點這里就不在贅述了。在控制器內部首先import兩個頭文件,<AddressBook/AddressBook.h> 和 <AddressBookUI/AddressBookUI.h>,如下所示:

//  ZBSampleViewController.m
//  ZBAddressBookDemo
//
//  Created by zhangb on 16/02/04.
//  Copyright (c) 2016年 mbp. All rights reserved.
//

#import "ZBSampleViewController.h"
#import <AddressBook/AddressBook.h>
#import <AddressBookUI/AddressBookUI.h>

首先為了方便演示與操作,這里就以兩個按鈕的操作代替具體的訪問過程,當然具體操作要具體分析,這里只是記錄訪問通訊錄,包括:

    1. 查看聯系人
    1. 向通訊錄內添加聯系人。
      下面是代碼示例:ABPeoplePickerNavigationController為展示系統通訊錄的控制器,并且需要遵循其代理方法。
#define IS_iOS8 [[UIDevice currentDevice].systemVersion floatValue] >= 8.0f
#define IS_iOS6 [[UIDevice currentDevice].systemVersion floatValue] >= 6.0f

@interface ZBSampleViewController ()<ABPeoplePickerNavigationControllerDelegate>{

    ABPeoplePickerNavigationController *_abPeoplePickerVc;
    NSMutableDictionary                *_infoDictionary;
    
}
@end
- (void)viewDidLoad {
    [super viewDidLoad];
    
    //1.打開通訊錄
    UIButton *openAddressBook = [UIButton buttonWithType:UIButtonTypeCustom];
    openAddressBook.frame = CGRectMake(100, 50, 100, 50);
    [openAddressBook setTitle:@"打開通訊錄" forState:UIControlStateNormal];
    openAddressBook.backgroundColor = [UIColor greenColor];
    [openAddressBook setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    [openAddressBook addTarget:self action:@selector(gotoAddressBook) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:openAddressBook];
    
    //2.添加聯系人
    UIButton *addContacts = [UIButton buttonWithType:UIButtonTypeCustom];
    addContacts.frame = CGRectMake(100, 150, 100, 50);
    [addContacts setTitle:@"添加聯系人" forState:UIControlStateNormal];
    addContacts.backgroundColor = [UIColor greenColor];
    [addContacts setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    [addContacts addTarget:self action:@selector(gotoAddContacts) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:addContacts];

}

打開系統通訊錄方法為openAddressBook按鈕的點擊事件,請忽略按鈕的樣式O(∩_∩)O~;
下面的IS_iOS8為我定義的宏,判斷系統的版本(上面有代碼示例)。

/**
 打開通訊錄
 */
- (void)gotoAddressBook{
    
    _abPeoplePickerVc = [[ABPeoplePickerNavigationController alloc] init];
    _abPeoplePickerVc.peoplePickerDelegate = self;
    
    //下面的判斷是ios8之后才需要加的,不然會自動返回app內部
    if(IS_iOS8){
        
        //predicateForSelectionOfPerson默認是true (當你點擊某個聯系人查看詳情的時候會返回app),如果你默認為true 但是實現-peoplePickerNavigationController:didSelectPerson:property:identifier:代理方法也是可以的,與此同時不能實現peoplePickerNavigationController: didSelectPerson:不然還是會返回app。
        //總之在ios8之后加上此句比較穩妥
        _abPeoplePickerVc.predicateForSelectionOfPerson = [NSPredicate predicateWithValue:false];
        
//        predicateForSelectionOfProperty默認是true (當你點擊某個聯系人的某個屬性的時候會返回app),此方法只要是默認值,無論你代理方法實現與否都會返回app。
        _abPeoplePickerVc.predicateForSelectionOfProperty = [NSPredicate predicateWithValue:false];
        
        //predicateForEnablingPerson默認是true,當設置為false時,所有的聯系人都不能被點擊。
//        _abPeoplePickerVc.predicateForEnablingPerson = [NSPredicate predicateWithValue:true];
    }
    [self presentViewController:_abPeoplePickerVc animated:YES completion:nil];
    
}

這里需要注意的是:
在iOS8之后需要加_abPeoplePickerVc.predicateForSelectionOfPerson = [NSPredicate predicateWithValue:false];這句代碼,不然當你選擇通訊錄中的某個聯系人的時候會直接返回app內部(類似crash)。predicateForSelectionOfPerson默認是true (當你點擊某個聯系人查看詳情的時候會返回app),如果你默認為true 但是實現-peoplePickerNavigationController:didSelectPerson:property:identifier:代理方法也是可以的,與此同時不能實現peoplePickerNavigationController: didSelectPerson:不然還是會返回app。_abPeoplePickerVc.predicateForSelectionOfProperty = [NSPredicate predicateWithValue:false];
作用同上。但是_abPeoplePickerVc.predicateForEnablingPerson 的斷言語句必須為true,否則任何聯系人你都不能選擇。上面的代碼中也有詳細描述。

#pragma mark - ABPeoplePickerNavigationController的代理方法

- (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier {
    
    ABMultiValueRef phone = ABRecordCopyValue(person, kABPersonPhoneProperty);
    
    long index = ABMultiValueGetIndexForIdentifier(phone,identifier);
    
    NSString *phoneNO = (__bridge NSString *)ABMultiValueCopyValueAtIndex(phone, index);
    [phoneNO stringByReplacingOccurrencesOfString:@"-" withString:@""];
    if (phone && phoneNO.length == 11) {
        //TODO:獲取電話號碼要做的事情
         
        [peoplePicker dismissViewControllerAnimated:YES completion:nil];
        return;
    }else{
        if (IS_iOS8){
            UIAlertController *tipVc = [UIAlertController alertControllerWithTitle:nil message:@"請選擇正確手機號" preferredStyle:UIAlertControllerStyleAlert];
            UIAlertAction *cancleAction = [UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
                [self dismissViewControllerAnimated:YES completion:nil];
            }];
            [tipVc addAction:cancleAction];
            [self presentViewController:tipVc animated:YES completion:nil];
            
        }else{
            UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:nil message:@"請選擇正確手機號" delegate:self cancelButtonTitle:@"確定" otherButtonTitles:nil];
            [alertView show];
        }
        //非ARC模式需要釋放對象
//        [alertView release];
    }
}

- (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController*)peoplePicker didSelectPerson:(ABRecordRef)person NS_AVAILABLE_IOS(8_0)
{
    ABPersonViewController *personViewController = [[ABPersonViewController alloc] init];
    personViewController.displayedPerson = person;
    
    [peoplePicker pushViewController:personViewController animated:YES];
    //非ARC模式需要釋放對象
//    [personViewController release];
}

/**
 peoplePickerNavigationController點擊取消按鈕時調用
 */
- (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker
{
    [peoplePicker dismissViewControllerAnimated:YES completion:nil];
}

/**
 iOS8被廢棄了,iOS8前查看聯系人必須實現(點擊聯系人可以繼續操作)
 */
- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person NS_DEPRECATED_IOS(2_0, 8_0)
{
    return YES;
}

/**
 iOS8被廢棄了,iOS8前查看聯系人屬性必須實現(點擊聯系人屬性可以繼續操作)
 */
- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier NS_DEPRECATED_IOS(2_0, 8_0)
{
    ABMultiValueRef phone = ABRecordCopyValue(person, kABPersonPhoneProperty);
    
    long index = ABMultiValueGetIndexForIdentifier(phone,identifier);
    
    NSString *phoneNO = (__bridge NSString *)ABMultiValueCopyValueAtIndex(phone, index);
    phoneNO = [phoneNO stringByReplacingOccurrencesOfString:@"-" withString:@""];
    NSLog(@"%@", phoneNO);
    if (phone && phoneNO.length == 11) {
        //TODO:獲取電話號碼要做的事情
        
        [peoplePicker dismissViewControllerAnimated:YES completion:nil];
        return NO;
    }else{
        if (IS_iOS8){
            UIAlertController *tipVc = [UIAlertController alertControllerWithTitle:nil message:@"請選擇正確手機號" preferredStyle:UIAlertControllerStyleAlert];
            UIAlertAction *cancleAction = [UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
                [self dismissViewControllerAnimated:YES completion:nil];
            }];
            [tipVc addAction:cancleAction];
            [self presentViewController:tipVc animated:YES completion:nil];
            
        }else{
            UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:nil message:@"請選擇正確手機號" delegate:self cancelButtonTitle:@"確定" otherButtonTitles:nil];
            [alertView show];
        }
    }
    return YES;
}

ABPeoplePickerNavigationController的代理方法也很好理解,看字面意思就能夠猜出代理方法的執行時間與能夠做什么。拿第一個代理方法說明一下,也就是- (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier;第一個參數就不用說了,第二個參數ABRecordRef 這是一個聯系人的引用也可以說是一個記錄,你可以理解為一個聯系人。第三個參數是聯系人附帶屬性的ID,其實ABPropertyID是個int類型值。第四個參數是多值屬性的標簽。

ABRecordCopyValue(ABRecordRef record, ABPropertyID property)返回一個CFTypeRef類型。此方法是從系統的通訊錄內,copy出用戶所選擇的某個聯系人數據。返回類型要看參數傳遞的是什么,第一個參數是聯系人記錄,第二個參數是參數ID,也就是用戶選擇的聯系人的某個屬性的ID。kABPersonPhoneProperty代表的是手機號碼屬性的ID,假如上面的ABRecordCopyValue的第二個參數傳遞kABPersonAddressProperty,則返回的是聯系人的地址屬性。下面是效果圖(因為是模擬器和真機有些差異)。

讀取聯系人.gif

下面介紹下,向系統通訊錄內添加聯系人。這里我只設置了聯系人的三個屬性:名字,電話,郵件,并將屬性存在了字典里。

-(instancetype)init{
    if (self = [super init]) {
        _infoDictionary = [NSMutableDictionary dictionaryWithCapacity:0];
        [_infoDictionary setObject:@"張三" forKey:@"name"];
        [_infoDictionary setObject:@"13000000000" forKey:@"phone"];
        [_infoDictionary setObject:@"1000000000@qq.com" forKey:@"email"];
    }
    return self;
}

因為蘋果越來越注重保護用戶的隱私,現在需要修改系統通訊錄內的聯系人信息時,必須要用戶授權才可以進行。授權鑒定代碼為:

ABAddressBookRequestAccessWith
Completion
(ABAddressBookRef addressBook,
ABAddressBookRequestAccessCompletionHandler completion)__OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_6_0);

下面的代碼中都有詳細描述。

/**
 添加聯系人
 */
- (void)gotoAddContacts{
    
    //添加到通訊錄,判斷通訊錄是否存在
    if ([self isExistContactPerson]) {//存在,返回
        //提示
        if (IS_iOS8) {
            UIAlertController *tipVc  = [UIAlertController alertControllerWithTitle:@"提示" message:@"聯系人已存在..." preferredStyle:UIAlertControllerStyleAlert];
            UIAlertAction *cancleAction = [UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
                [self dismissViewControllerAnimated:YES completion:nil];
            }];
            [tipVc addAction:cancleAction];
            [self presentViewController:tipVc animated:YES completion:nil];
        }else{
            UIAlertView *tip = [[UIAlertView alloc] initWithTitle:@"提示" message:@"聯系人已存在..." delegate:self cancelButtonTitle:@"確定" otherButtonTitles:nil, nil];
            [tip show];
            //        [tip release];
        }
        return;
    }else{//不存在  添加
        [self creatNewRecord];
    }
}

- (BOOL)isExistContactPerson{
    //這個變量用于記錄授權是否成功,即用戶是否允許我們訪問通訊錄
    int __block tip=0;
    
    BOOL __block isExist = NO;
    //聲明一個通訊簿的引用
    ABAddressBookRef addBook =nil;
    //因為在IOS6.0之后和之前的權限申請方式有所差別,這里做個判斷
    if (IS_iOS6) {
        //創建通訊簿的引用,第一個參數暫時寫NULL,官方文檔就是這么說的,后續會有用,第二個參數是error參數
        CFErrorRef error = NULL;
        addBook=ABAddressBookCreateWithOptions(NULL, &error);
        //創建一個初始信號量為0的信號
        dispatch_semaphore_t sema=dispatch_semaphore_create(0);
        //申請訪問權限
        ABAddressBookRequestAccessWithCompletion(addBook, ^(bool greanted, CFErrorRef error)        {
            //greanted為YES是表示用戶允許,否則為不允許
            if (!greanted) {
                tip=1;
                
            }else{
                //獲取所有聯系人的數組
                CFArrayRef allLinkPeople = ABAddressBookCopyArrayOfAllPeople(addBook);
                //獲取聯系人總數
                CFIndex number = ABAddressBookGetPersonCount(addBook);
                //進行遍歷
                for (NSInteger i=0; i<number; i++) {
                    //獲取聯系人對象的引用
                    ABRecordRef  people = CFArrayGetValueAtIndex(allLinkPeople, i);
                    //獲取當前聯系人名字
                    NSString*firstName=(__bridge NSString *)(ABRecordCopyValue(people, kABPersonFirstNameProperty));
                    
                    if ([firstName isEqualToString:[_infoDictionary objectForKey:@"name"]]) {
                        isExist = YES;
                    }
                    
//                    //獲取當前聯系人姓氏
//                    NSString*lastName=(__bridge NSString *)(ABRecordCopyValue(people, kABPersonLastNameProperty));

//獲取當前聯系人中間名
//                    NSString*middleName=(__bridge NSString*)(ABRecordCopyValue(people, kABPersonMiddleNameProperty));
//                    //獲取當前聯系人的名字前綴
//                    NSString*prefix=(__bridge NSString*)(ABRecordCopyValue(people, kABPersonPrefixProperty));
//                    //獲取當前聯系人的名字后綴
//                    NSString*suffix=(__bridge NSString*)(ABRecordCopyValue(people, kABPersonSuffixProperty));
//                    //獲取當前聯系人的昵稱
//                    NSString*nickName=(__bridge NSString*)(ABRecordCopyValue(people, kABPersonNicknameProperty));
//                    //獲取當前聯系人的名字拼音
//                    NSString*firstNamePhoneic=(__bridge NSString*)(ABRecordCopyValue(people, kABPersonFirstNamePhoneticProperty));
//                    //獲取當前聯系人的姓氏拼音
//                    NSString*lastNamePhoneic=(__bridge NSString*)(ABRecordCopyValue(people, kABPersonLastNamePhoneticProperty));
//                    //獲取當前聯系人的中間名拼音
//                    NSString*middleNamePhoneic=(__bridge NSString*)(ABRecordCopyValue(people, kABPersonMiddleNamePhoneticProperty));
//                    //獲取當前聯系人的公司
//                    NSString*organization=(__bridge NSString*)(ABRecordCopyValue(people, kABPersonOrganizationProperty));
//                    //獲取當前聯系人的職位
//                    NSString*job=(__bridge NSString*)(ABRecordCopyValue(people, kABPersonJobTitleProperty));
//                    //獲取當前聯系人的部門
//                    NSString*department=(__bridge NSString*)(ABRecordCopyValue(people, kABPersonDepartmentProperty));
//                    //獲取當前聯系人的生日
//                    NSString*birthday=(__bridge NSDate*)(ABRecordCopyValue(people, kABPersonBirthdayProperty));
//                    NSMutableArray * emailArr = [[NSMutableArray alloc]init];
//                    //獲取當前聯系人的郵箱 注意是數組
//                    ABMultiValueRef emails= ABRecordCopyValue(people, kABPersonEmailProperty);
//                    for (NSInteger j=0; j<ABMultiValueGetCount(emails); j++) {
//                        [emailArr addObject:(__bridge NSString *)(ABMultiValueCopyValueAtIndex(emails, j))];
//                    }
//                    //獲取當前聯系人的備注
//                    NSString*notes=(__bridge NSString*)(ABRecordCopyValue(people, kABPersonNoteProperty));
//                    //獲取當前聯系人的電話 數組
//                    NSMutableArray * phoneArr = [[NSMutableArray alloc]init];
//                    ABMultiValueRef phones= ABRecordCopyValue(people, kABPersonPhoneProperty);
//                    for (NSInteger j=0; j<ABMultiValueGetCount(phones); j++) {
//                        [phoneArr addObject:(__bridge NSString *)(ABMultiValueCopyValueAtIndex(phones, j))];
//                    }
//                    //獲取創建當前聯系人的時間 注意是NSDate
//                    NSDate*creatTime=(__bridge NSDate*)(ABRecordCopyValue(people, kABPersonCreationDateProperty));
//                    //獲取最近修改當前聯系人的時間
//                    NSDate*alterTime=(__bridge NSDate*)(ABRecordCopyValue(people, kABPersonModificationDateProperty));
//                    //獲取地址
//                    ABMultiValueRef address = ABRecordCopyValue(people, kABPersonAddressProperty);
//                    for (int j=0; j<ABMultiValueGetCount(address); j++) {
//                        //地址類型
//                        NSString * type = (__bridge NSString *)(ABMultiValueCopyLabelAtIndex(address, j));
//                        NSDictionary * temDic = (__bridge NSDictionary *)(ABMultiValueCopyValueAtIndex(address, j));
//                        //地址字符串,可以按需求格式化
//                        NSString * adress = [NSString stringWithFormat:@"國家:%@\n省:%@\n市:%@\n街道:%@\n郵編:%@",[temDic valueForKey:(NSString*)kABPersonAddressCountryKey],[temDic valueForKey:(NSString*)kABPersonAddressStateKey],[temDic valueForKey:(NSString*)kABPersonAddressCityKey],[temDic valueForKey:(NSString*)kABPersonAddressStreetKey],[temDic valueForKey:(NSString*)kABPersonAddressZIPKey]];
//                    }
//                    //獲取當前聯系人頭像圖片
//                    NSData*userImage=(__bridge NSData*)(ABPersonCopyImageData(people));
//                    //獲取當前聯系人紀念日
//                    NSMutableArray * dateArr = [[NSMutableArray alloc]init];
//                    ABMultiValueRef dates= ABRecordCopyValue(people, kABPersonDateProperty);
//                    for (NSInteger j=0; j<ABMultiValueGetCount(dates); j++) {
//                        //獲取紀念日日期
//                        NSDate * data =(__bridge NSDate*)(ABMultiValueCopyValueAtIndex(dates, j));
//                        //獲取紀念日名稱
//                        NSString * str =(__bridge NSString*)(ABMultiValueCopyLabelAtIndex(dates, j));
//                        NSDictionary * temDic = [NSDictionary dictionaryWithObject:data forKey:str];
//                        [dateArr addObject:temDic];
//                    }
                }
                
                
            }
            //發送一次信號
            dispatch_semaphore_signal(sema);
        });
        //等待信號觸發
        dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
    }else{
        
        //IOS6之前
        addBook =ABAddressBookCreate();
        
        //獲取所有聯系人的數組
        CFArrayRef allLinkPeople = ABAddressBookCopyArrayOfAllPeople(addBook);
        //獲取聯系人總數
        CFIndex number = ABAddressBookGetPersonCount(addBook);
        //進行遍歷
        for (NSInteger i=0; i<number; i++) {
            //獲取聯系人對象的引用
            ABRecordRef  people = CFArrayGetValueAtIndex(allLinkPeople, i);
            //獲取當前聯系人名字
            NSString*firstName=(__bridge NSString *)(ABRecordCopyValue(people, kABPersonFirstNameProperty));
            
            if ([firstName isEqualToString:[_infoDictionary objectForKey:@"name"]]) {
                isExist = YES;
            }
        }
    }
    
    if (tip) {
        //設置提示
        if (IS_iOS8) {
            UIAlertController *tipVc  = [UIAlertController alertControllerWithTitle:@"友情提示" message:@"請您設置允許APP訪問您的通訊錄\nSettings>General>Privacy" preferredStyle:UIAlertControllerStyleAlert];
            UIAlertAction *cancleAction = [UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
                [self dismissViewControllerAnimated:YES completion:nil];
            }];
            [tipVc addAction:cancleAction];
            [tipVc presentViewController:tipVc animated:YES completion:nil];
        }else{
            UIAlertView * alart = [[UIAlertView alloc]initWithTitle:@"友情提示" message:@"請您設置允許APP訪問您的通訊錄\nSettings>General>Privacy" delegate:self cancelButtonTitle:@"確定" otherButtonTitles:nil, nil];
            [alart show];
            //非ARC
//            [alart release];
        }
    }
    return isExist;
}

//創建新的聯系人
- (void)creatNewRecord
{
    CFErrorRef error = NULL;
    
    //創建一個通訊錄操作對象
    ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error);
    
    //創建一條新的聯系人紀錄
    ABRecordRef newRecord = ABPersonCreate();
    
    //為新聯系人記錄添加屬性值
    ABRecordSetValue(newRecord, kABPersonFirstNameProperty, (__bridge CFTypeRef)[_infoDictionary objectForKey:@"name"], &error);
    
    //創建一個多值屬性(電話)
    ABMutableMultiValueRef multi = ABMultiValueCreateMutable(kABMultiStringPropertyType);
    ABMultiValueAddValueAndLabel(multi, (__bridge CFTypeRef)[_infoDictionary objectForKey:@"phone"], kABPersonPhoneMobileLabel, NULL);
    ABRecordSetValue(newRecord, kABPersonPhoneProperty, multi, &error);
    
    //添加email
    ABMutableMultiValueRef multiEmail = ABMultiValueCreateMutable(kABMultiStringPropertyType);
    ABMultiValueAddValueAndLabel(multiEmail, (__bridge CFTypeRef)([_infoDictionary objectForKey:@"email"]), kABWorkLabel, NULL);
    ABRecordSetValue(newRecord, kABPersonEmailProperty, multiEmail, &error);
    
    
    //添加記錄到通訊錄操作對象
    ABAddressBookAddRecord(addressBook, newRecord, &error);
    
    //保存通訊錄操作對象
    ABAddressBookSave(addressBook, &error);
    
    //通過此接口訪問系統通訊錄
    ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
        
        if (granted) {
            //顯示提示
            if (IS_iOS8) {
                UIAlertController *alertVc = [UIAlertController alertControllerWithTitle:@"添加成功" message:nil preferredStyle:UIAlertControllerStyleAlert];
                UIAlertAction *alertAction = [UIAlertAction actionWithTitle:@"知道了" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
                    [self dismissViewControllerAnimated:YES completion:nil];
                    
                }];
                [alertVc addAction:alertAction];
                [self presentViewController:alertVc animated:YES completion:nil];
            }else{
            
                UIAlertView *tipView = [[UIAlertView alloc] initWithTitle:nil message:@"添加成功" delegate:self cancelButtonTitle:@"知道了" otherButtonTitles:nil, nil];
                [tipView show];
                //非ARC
//                [tipView release];
            }
        }
    });
    
    CFRelease(multiEmail);
    CFRelease(multi);
    CFRelease(newRecord);
    CFRelease(addressBook);
}

代碼中有每個步驟都有對應的注釋,對應看起來會容易一些!下面是效果圖:

添加聯系人.gif

如果需要添加聯系人的其他屬性,方法類似,只是屬性名不同。慢慢挖掘吧,伙伴們!

聲明:此文僅為了記錄本人開發中的遇到并解決的問題,權當是一篇筆記,并不是教學blog,不免會有錯誤,如有煩請指正,大家共同學習!謝謝!

下面列舉一些參考blog:(再次感謝無私分享的coder)
http://m.open-open.com/m/code/view/1432302834146
http://supershll.blog.163.com/blog/static/37070436201272821810474/
http://www.tuicool.com/articles/Mvuu6z

注意:iOS10以及Xcode8的緣故,需要適配,需要添加訪問權限設置,也就是在info.plist中添加key:Privacy - Contacts Usage Description value:對應的value值可以隨便寫,不然程序會崩潰!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,578評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,701評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,691評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,974評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,694評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,026評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,015評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,193評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,719評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,442評論 3 360
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,668評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,151評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,846評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,255評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,592評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,394評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,635評論 2 380

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,836評論 18 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,771評論 25 708
  • 國家電網公司企業標準(Q/GDW)- 面向對象的用電信息數據交換協議 - 報批稿:20170802 前言: 排版 ...
    庭說閱讀 11,079評論 6 13
  • 為什么要上傳到JCenter 為了一句話依賴 注冊bintray賬號 既然是通過bintray上傳,那得先注冊bi...
    X_Sation閱讀 792評論 4 2
  • (索科洛夫/文) 我多么希望,這幾行詩 忘記它們自己是一些字 而成為濕潤的林蔭道上的 樹木、天空、清風和房子 但愿...
    辛艷平閱讀 4,164評論 0 1