iOS9.0 系统通讯录

在iOS的9.0系统之后,系统的通讯录框架使用了Contacts/Contacts.hContactsUI/ContactsUI.h,替换了AddressBook/AddressBook.hAddressBookUI/AddressBookUI.h

一、系统联系人界面

下面就来简单介绍一下ContactsUI/ContactsUI.h的使用
1、ContactsUI/ContactsUI.h是系统自带UI的通讯录界面,我们不用去获取联系人数据,直接利用系统的UI界面就能够展示联系人界面。
2、首先导入头文件 #import
3、展示界面
// 1.创建通讯录界面(自带系统UI界面)

// 真机或者模拟器的系统版本必须是9.0以上
CNContactPickerViewController *picketVC = [[CNContactPickerViewController alloc] init]; 
// 2.遵守代理 CNContactPickerDelegate
picketVC.delegate = self;
// 3.展现通讯录界面
[self presentViewController:picketVC animated:YES completion:nil];

5、代理方法有5个,iOS9之后系统支持多选和单选2中情况:

// 取消代理方法
- (void)contactPickerDidCancel:(CNContactPickerViewController *)picker;
// 单选代理方法
- (void)contactPicker:(CNContactPickerViewController *)picker didSelectContact:(CNContact *)contact;
- (void)contactPicker:(CNContactPickerViewController *)picker didSelectContactProperty:(CNContactProperty *)contactProperty;
// 多选代理方法
- (void)contactPicker:(CNContactPickerViewController *)picker didSelectContacts:(NSArray *)contacts;
- (void)contactPicker:(CNContactPickerViewController *)picker didSelectContactProperties:(NSArray *)contactProperties;

6、带附属属性展示界面
CNContactPickerViewController控制器有几个属性值:分别是
(1)displayedPropertyKeys,
(2)predicateForEnablingContact,
(3)predicateForSelectionOfContact,
(4)predicateForSelectionOfProperty
展示界面代码创建如下:

// 1.创建通讯录界面(自带系统UI界面),真机或者模拟器的系统版本必须是9.0以上
CNContactPickerViewController *picketVC = [[CNContactPickerViewController alloc] init]; 
// 2.遵守代理 CNContactPickerDelegate
picketVC.delegate = self;
// (1)picketVC.displayedPropertyKeys属性 进入联系人详情界面时需要展示的信息(必须在展示界面之前设置), displayedPropertyKeys不设置的话,会展示所有信息,如果设置的话,则只会根据数组中的信息进行展示,但是这个属性只适用于单选的状态,多选状态下不起作用。
picketVC.displayedPropertyKeys = @[CNContactGivenNameKey,CNContactPhoneNumbersKey,CNContactEmailAddressesKey];
// (2)picketVC.predicateForSelectionOfContact属性 用于控制联系人选中后的操作
picketVC.predicateForSelectionOfContact = [NSPredicate predicateWithFormat:@"emailAddresses.@count == 1"];
// (3)picketVC.predicateForSelectionOfProperty属性 用于控制联系人属性选中后的操作
picketVC.predicateForSelectionOfProperty = [NSPredicate predicateWithFormat:@"(key == 'emailAddresses') AND (value LIKE '*@mac.com')"]; // 也可以是@qq.com
// (4)picketVC.predicateForEnablingContact属性 用于控制联系人是否可以选择,如果不设置,默认所有的联系人都是可以交互的(可选中),如果设置了并且命中,则联系人不可交互,不命中的话,可以交互。此属性在多选和单选情况下都起作用
picketVC.predicateForEnablingContact = [NSPredicate predicateWithFormat:@"emailAddresses.@count > 0"];
// 3.展现通讯录界面
[self presentViewController:picketVC animated:YES completion:nil];
属性是有NSPredicate谓词类创建的,这个可以根据CNContactPickerViewController中属性的表述进行创建,比如NSPredicate *predicateForSelectionOfContact; // e.g. emailAddresses.@count == 1,emailAddresses.@count == 1就是描述字段 

7、代理方法的实现
(1)取消代理方法

//点击cancel按钮时被调用(多选状态时,在Done按钮的左侧,单选,多选点击cancel按钮时,都会被调用)
- (void)contactPickerDidCancel:(CNContactPickerViewController *)picker{
    NSLog(@"%s",__func__);
}

下面的4个代理方法只需要实现其中的一个就可以,分为单选(一次只能选中一个联系人),多选(同时选中多个联系人)2中情况,如果2种状态同时实现,则多选的优先级比较高,即首先调用多选联系人界面

(2)单选代理方法

// 如果单选状态下的2个方法同时实现,即实现
- (void)contactPicker:(CNContactPickerViewController *)picker didSelectContact:(CNContact *)contact;
- (void)contactPicker:(CNContactPickerViewController *)picker didSelectContactProperty:(CNContactProperty *)contactProperty;

1、第一个方法会优先调用
2、只实现第一个方法,点击某一个联系人,则直接会dismiss掉联系人界面
3、只实现第二个方法,点击某一个联系人会直接进入到联系人详情界面,并且受displayedPropertyKeys属性约束

#pragma mark - 单选
// 只实现这个方法,选中某一个联系人的时候调用,在选中联系人后,联系人界面自动dismiss掉
- (void)contactPicker:(CNContactPickerViewController *)picker didSelectContact:(CNContact *)contact{

    NSLog(@"%s",__func__);

    // 如果picker.predicateForSelectionOfContact没有设置,在选中联系人后,联系人界面自动dismiss掉,此方法会被调用
    // 如果picker.predicateForSelectionOfContact有设置,并且命中了,联系人界面自动dismiss掉,此方法会被调用,如果没有命中,此方法不会被调用,则进入到联系人详情界面(联系人详情界面受displayedPropertyKeys属性约束)

    // 在这里,我选择进入到联系人详情界面,并且详情界面的展示信息不受displayedPropertyKeys属性约束,在选中某一个属性的时候,就会调用系统的操作,比如点击了电话号码,则会直接拨打电话
    // CNContactViewController *vc = [CNContactViewController viewControllerForContact:contact];
    // [self.navigationController pushViewController:vc animated:YES];

}

// 只实现这个方法,点击某一个联系人会直接进入到联系人详情界面,并且受displayedPropertyKeys属性约束,在联系人详情界面中,选中某一个属性的时候调用,在选中属性后,详情界面会自动dismiss掉
- (void)contactPicker:(CNContactPickerViewController *)picker didSelectContactProperty:(CNContactProperty *)contactProperty{

    // 如果picker.predicateForSelectionOfProperty没有设置,在选中联系人后,联系人界面自动dismiss掉,此方法会被调用
    // 如果picker.predicateForSelectionOfProperty有设置,并且命中了,联系人详情界面自动dismiss掉,此方法会被调用,如果没有命中,则此方法不会被调用,联系人详情界面不会dismiss掉(联系人详情界面受displayedPropertyKeys属性约束)

    //在选中某一个属性的时候,如果在方法中不做任何操作的话,则直接会dismiss掉,比如点击了电话号码,则会直接把控制器dismiss,而不是去拨打电话(predicateForSelectionOfProperty没有设置或者设置并命中)。

    NSLog(@"%s",__func__);
    // contactProperty.key(选中属性的键名),contactProperty.value(选中属性的属性,可以根据属性类型进行各种操作)
    NSLog(@"%@,%@",contactProperty.key,contactProperty.value);
}

(3)多选代理方法

#pragma mark - 多选
// 如果多选状态下的2个方法同时实现,即实现
- (void)contactPicker:(CNContactPickerViewController *)picker didSelectContacts:(NSArray *)contacts;
- (void)contactPicker:(CNContactPickerViewController *)picker didSelectContactProperties:(NSArray *)contactProperties;

1、第一个方法会优先调用
2、只实现第一个方法,在点击Done按钮的时候则直接会dismiss掉联系人界面
3、只实现第二个方法,在点击Done按钮的时候则直接会dismiss掉联系人界面

// 只实现这个方法,只要点击done之后,就会被调用(选中联系人的时候或者没有选择的时候都会),联系人界面会自动dismiss掉
- (void)contactPicker:(CNContactPickerViewController *)picker didSelectContacts:(NSArray *)contacts{ 
    // predicateForSelectionOfContact,predicateForSelectionOfProperty属性 不影响

    NSLog(@"%s,%lu",__func__,contacts.count);
   
//    CNContactViewController *vc = [CNContactViewController viewControllerForContact:[contacts lastObject]];
//    [self.navigationController pushViewController:vc animated:YES];  
}


// 只实现这个方法,选中联系人的时候被调用(可以多选)点击done之后,联系人界面会自动dismiss掉
- (void)contactPicker:(CNContactPickerViewController *)picker didSelectContactProperties:(NSArray *)contactProperties{

    NSLog(@"%s",__func__);
    NSLog(@"%@,%@",[contactProperties lastObject].key,[contactProperties lastObject].value);
    // picker.predicateForSelectionOfContact属性 不影响
    // 如果picker.predicateForSelectionOfProperty没有设置,所有的联系人都可以被选中
    // 如果picker.predicateForSelectionOfProperty有设置,并且命中了,联系人能被选中,不命中的话不能被选中
}

在除了取消代理方法外的其余4个方法,只要实现一个就可以了,如果同时实现多选和单选代理方法,则多选代理的优先级比较高,如果同时实现单选(多选)代理方法,则选择联系人的方法优先级高。

二、获取系统联系人全部数据

/** 读取联系人 */
- (void)readContact {
    
    if (@available(iOS 9.0, *)) {
        // 获取指定的字段,并不是要获取所有字段,需要指定具体的字段
        NSArray *keyToFetch = @[CNContactGivenNameKey, CNContactFamilyNameKey, CNContactPhoneNumbersKey];
        CNContactFetchRequest *fetchRequest = [[CNContactFetchRequest alloc] initWithKeysToFetch:keyToFetch];
        CNContactStore *contactStore = [[CNContactStore alloc] init];
        
        [contactStore enumerateContactsWithFetchRequest:fetchRequest error:nil usingBlock:^(CNContact * _Nonnull contact, BOOL * _Nonnull stop) {
            
            NSLog(@"---------------------------------");
            NSString *givename = contact.givenName;
            NSString *familyname = contact.familyName;
            NSLog(@"%@%@", familyname, givename);
            
            NSString *name = [NSString stringWithFormat:@"%@%@", contact.familyName, contact.givenName];
            
            NSArray *phoneArray = contact.phoneNumbers;
            CNPhoneNumber *phone = [[CNPhoneNumber alloc] initWithStringValue:@"leo"];
            for (CNLabeledValue *labelvalue in phoneArray) {
                phone = labelvalue.value;
                NSLog(@"phone:%@", phone.stringValue);
            }
            
            [self.contactDic setObject:phone.stringValue forKey:name];
        }];
    } else {
        // Fallback on earlier versions
        // 创建通讯录对象
        ABAddressBookRef bookRef = ABAddressBookCreate();
        // 获取通讯录中所有的联系人
        CFArrayRef arrayRef = ABAddressBookCopyArrayOfAllPeople(bookRef);
        // 遍历所有联系人
        CFIndex count = CFArrayGetCount(arrayRef);
        for (int i = 0; i < count; i++)
        {
            ABRecordRef record = CFArrayGetValueAtIndex(arrayRef, i);
            
            // 获取姓名
            NSString *firstName = (__bridge_transfer NSString *)ABRecordCopyValue(record, kABPersonFirstNameProperty);
            NSString *lastName = (__bridge_transfer NSString *)ABRecordCopyValue(record, kABPersonLastNameProperty);
            NSLog(@"firstName = %@, lastName = %@", firstName, lastName);
            
            // 获取电话号码
            ABMultiValueRef multiValue = ABRecordCopyValue(record, kABPersonPhoneProperty);
            CFIndex count = ABMultiValueGetCount(multiValue);
            for (int i = 0; i < count; i ++)
            {
                NSString *label = (__bridge_transfer NSString *)ABMultiValueCopyLabelAtIndex(multiValue, i);
                NSString *phone = (__bridge_transfer NSString *)ABMultiValueCopyValueAtIndex(multiValue, i);
                NSLog(@"label = %@, phone = %@", label, phone);
            }
            
            CFRelease(multiValue);
        }
        CFRelease(bookRef);
        CFRelease(arrayRef);
    }
}

/** 写入联系人 */
- (void)writeContact {
    
    if (@available(iOS 9.0, *)) {
        // 创建对象
        // 这个里面可以添加多个电话,email,地址等等。 感觉使用率不高,只提供了最常用的属性:姓名+电话,需要时可以自行扩展。
        CNMutableContact *contact = [[CNMutableContact alloc] init];
        contact.givenName = @"leo";
        CNLabeledValue *phone = [CNLabeledValue labeledValueWithLabel:CNLabelPhoneNumberMobile value:[CNPhoneNumber phoneNumberWithStringValue:@"10086"]];
        contact.phoneNumbers = @[phone];
        
        // 把对象加到请求中
        CNSaveRequest *request = [[CNSaveRequest alloc] init];
        [request addContact:contact toContainerWithIdentifier:nil];
        // 执行请求
        CNContactStore *store = [[CNContactStore alloc] init];
        [store executeSaveRequest:request error:nil];
    } else {
        // Fallback on earlier versions
        NSString *name = @"ileo";
        NSString *phone = @"10087";
        CFErrorRef error = NULL;
        
        ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error);
        ABRecordRef newRecord = ABPersonCreate();
        ABRecordSetValue(newRecord, kABPersonFirstNameProperty, (__bridge CFTypeRef)name, &error);
        
        ABMutableMultiValueRef multi = ABMultiValueCreateMutable(kABMultiStringPropertyType);
        ABMultiValueAddValueAndLabel(multi, (__bridge CFTypeRef)phone, kABPersonPhoneMobileLabel, NULL);
        ABRecordSetValue(newRecord, kABPersonPhoneProperty, multi, &error);
        CFRelease(multi);
        
        ABAddressBookAddRecord(addressBook, newRecord, &error);
        
        ABAddressBookSave(addressBook, &error);
        CFRelease(newRecord);
        CFRelease(addressBook);
    }
    
}

你可能感兴趣的:(iOS9.0 系统通讯录)