Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/102.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 需要创建一个自定义视图,如ABPeoplePickerNavigationController_Ios_Xcode_Contacts_Whatsapp_Abpeoplepickerview - Fatal编程技术网

Ios 需要创建一个自定义视图,如ABPeoplePickerNavigationController

Ios 需要创建一个自定义视图,如ABPeoplePickerNavigationController,ios,xcode,contacts,whatsapp,abpeoplepickerview,Ios,Xcode,Contacts,Whatsapp,Abpeoplepickerview,我想创建一个自定义视图,就像iPhone中的联系人一样。是否有任何教程可用于创建像ABPeoplePickerNavigationController一样的自定义视图 请注意,我不想打开AddressBookUI框架提供的默认人员选取器控制器。此外,我确实希望将此导航控制器绑定到我的主视图中 关于我想要的参考资料,您可以参考iOS设备上Whatsapp的联系人选项卡 编辑:我已经得到了一个联系人列表,并在表视图中显示了联系人的名字和姓氏。现在,我想为A-Z中的字母创建一个索引,点击该索引时,表视

我想创建一个自定义视图,就像iPhone中的联系人一样。是否有任何教程可用于创建像ABPeoplePickerNavigationController一样的自定义视图

请注意,我不想打开AddressBookUI框架提供的默认人员选取器控制器。此外,我确实希望将此导航控制器绑定到我的主视图中

关于我想要的参考资料,您可以参考iOS设备上Whatsapp的联系人选项卡

编辑:我已经得到了一个联系人列表,并在表视图中显示了联系人的名字和姓氏。现在,我想为A-Z中的字母创建一个索引,点击该索引时,表视图应该滚动到该联系人。另外,我如何实现搜索功能以按用户的名字或姓氏查找用户?

请查看以下内容:

“表视图”的方法可帮助您获得所需的结果:

- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView


我目前正在开发的应用程序中有着完全相同的东西,我们也从Whatsapp等应用程序中获得了灵感

我使用了一个带有自定义单元格的简单tableview作为视觉效果,其中只包含名称和图片

我的过程如下:

  • 在coredata中创建一个
    contact
    对象(或另一种保存数据的持久方式)
  • 通过
    ABAddressbook
    框架,您可以浏览所有联系人并将其转换为新联系人对象。在
    Contact
    对象中保留您的
    ABPerson
    的引用,这将允许您稍后仅使用引用来查找和更新您的联系人。如果你不这样做,你将不得不浏览到所有你的ABPersons每次你想更新你的联系人。 您可以直接使用ABPersons,但编写代码会非常痛苦

  • 提取完所有联系人后,如果使用核心数据,请确保保存上下文,或将其存储在.sqlite中

  • 然后,您只需在联系人数组中提取这些联系人,并在您选择的自定义单元格中显示这些联系人
是tableview教程中一个不错的自定义单元格。你可以通过谷歌搜索“tableview自定义单元格ios”并找到你可能喜欢的不同东西来找到更多。最后,您将得到一个带有标签和图片的单元格,您可以使用简单的
UITableViewCell
,我将其用于另一个“contact”类型的tableview

使联系人列表保持最新(获取正确的号码、图片、姓名等),并在更新之前确保它们存在,检查联系人是否已被删除、添加等。所有这些都必须完成,才能使您的列表准确,这是一个相当长/烦人的过程

我可以分享我的Contact类,但它包含了许多与您无关的代码,这可能会让您感到困惑,因为: -我还在检查这些联系人是否已经是我的应用程序的用户,以便在我的tableview的特定部分中移动他们 -我将tableview分为27个部分(用户,然后是字母)

还有,我将用最后一条一般编程建议来结束它:首先准确地写下你需要什么,你需要什么,把所有的可能性都写在纸上,等等,这将是一个好主意。我碰到了很多简单的问题,我花了一段时间才解决,要么是因为我计划不当,要么是因为它被隐藏了

例如:

  • 你的一些联系人根本没有名字
  • 您的一些联系人在“标题”字段中有一个姓名(您在此处填写医生或先生)
  • 您的某些联系人没有电话号码(如果您使用电话号码作为标识符)
  • 您的某些联系人具有国际格式,而某些联系人没有(+32 46556555或0032 46556555)
  • 你的一些联系人的照片是用相机拍摄的,另一些是Gmail的,格式不同
  • 由于用户同步不良,您可能有重复的联系人(相同的姓名,所有内容都相同)
  • 您需要确保firstname/lastname位于正确的部分,区分大小写的编码可能会导致问题
  • 您需要为以笑脸或非字母数字字符开头的联系人找到解决方案
  • 您的用户会希望在旁边有一个索引列表
  • 当然,你需要添加一个搜索栏,因为有些人有超过1000个联系人
  • 我保证还会有更多的人来
因为这是一个非常具体的应用程序,我不打算回顾我遇到的每一个问题以及我为此所做的一切,但你会得到这样的想法:)尽管可以自由地提出任何非常具体的问题,我可能已经有了一个非常具体的解决方案,因为我几乎必须从头开始复制whatsapp的联系人,而且,见鬼,我做到了。(我实际上得到了与匿名和iOS完全相同的结果)

编辑:这里有一些方法,我的ABPerson提取方法;ContactDAO主要与我的持久化模型(CoreData)交互,我相信它们的名称足够清晰,您可以理解发生了什么。我对这些评论和变化多端的名字很满意,所以你应该可以毫不费力地阅读它们

这里有一大块代码

- (NSMutableArray *)getAllRecordsWithPeople:(CFArrayRef)allPeople andAddressBook:(ABAddressBookRef)addressbook{
    NSMutableArray *newRecords = [[NSMutableArray alloc]init];
    CFIndex nPeople = ABAddressBookGetPersonCount(addressbook);

    for (int i=0;i < nPeople;i++){

        ABRecordRef ref = CFArrayGetValueAtIndex(allPeople,i);
        ABRecordID refId = ABRecordGetRecordID(ref);
        NSNumber *recId = [NSNumber numberWithInt:refId];
        [newRecords addObject:recId];
    }

    return newRecords;
}

- (void)getValidContactsFromAddressBookWithCompletionBlock:(void (^)(NSError *error))completion{

    ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, nil);

    __block BOOL accessGranted = NO;

    if (&ABAddressBookRequestAccessWithCompletion != NULL) {
        dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

        ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
            accessGranted = granted;
            dispatch_semaphore_signal(semaphore);
        });

        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    }

    if (accessGranted) {

        NSMutableArray *newRecords       = [[NSMutableArray alloc]init];
        NSMutableArray *updatedRecords   = [[NSMutableArray alloc]init];
        NSMutableArray *unchangedRecords = [[NSMutableArray alloc]init];

        CFArrayRef allPeople  = ABAddressBookCopyArrayOfAllPeople(addressBook);
        CFIndex nPeople       = ABAddressBookGetPersonCount(addressBook);

        //Checking the last time we updated
        NSTimeInterval lastSyncTime;
        if ([[NSUserDefaults standardUserDefaults]objectForKey:@"LastSyncTime"] == nil){
            //This is the first time we update.
            lastSyncTime = 0;
        }else{
            //Setting the last update in variable
            lastSyncTime = [[[NSUserDefaults standardUserDefaults]objectForKey:@"LastSyncTime"]doubleValue];
        }

        if (lastSyncTime == 0){
            //We have to insert everyone, this is the first time we do this.
            newRecords = [self getAllRecordsWithPeople:allPeople andAddressBook:addressBook];
        }else{
            //We have to manually compare everyone to see if something has changed.

            for (int i=0;i < nPeople;i++) {

                ABRecordRef ref = CFArrayGetValueAtIndex(allPeople,i);
                ABRecordID refId = ABRecordGetRecordID(ref);
                NSNumber *recId = @(refId);

                CFDateRef recordCreation = ABRecordCopyValue(ref, kABPersonCreationDateProperty);
                NSDate *recCreDate = (__bridge NSDate *)(recordCreation);
                NSTimeInterval creDateInterval = [recCreDate timeIntervalSince1970];

                if(creDateInterval > lastSyncTime){
                    //This object was created after my lastSync, this must be a new record
                    [newRecords addObject:recId];

                }else{

                    //Checking the last update of the given record
                    CFDateRef recordUpdate = ABRecordCopyValue(ref, kABPersonModificationDateProperty);
                    NSDate *recUpDate = (__bridge NSDate*)(recordUpdate);

                    if ([recUpDate timeIntervalSince1970] > lastSyncTime){
                        //The record was somehow updated since last time, we'll update it
                        [updatedRecords addObject:recId];

                    }else{
                        //The record wasn't updated nor created, it is therefore unchanged.
                        //We still need to keep it in a separate array to compare deleted contacts
                        [unchangedRecords addObject:recId];
                    }
                }

            }
            if(allPeople)
                CFRelease(allPeople);
        }

        [self manageNewContacts:newRecords updatedContacts:updatedRecords andUnchangedContacts:unchangedRecords inAddressBook:addressBook andBlock:^(NSError *error) {
            completion(error);
        }];
    }else{
        NSError *error = [NSError errorWithDomain:@"ABAccess access forbidden" code:403 userInfo:nil];
        completion(error);
    }
}

- (void)manageNewContacts:(NSMutableArray*)newRecords updatedContacts:(NSMutableArray*)updatedRecords andUnchangedContacts:(NSMutableArray*)unchangedRecords inAddressBook:(ABAddressBookRef)addressbook andBlock:(void (^)(NSError *error))completion{

    AppDelegate *app = [UIApplication sharedApplication].delegate;
    NSManagedObjectContext *context = app.managedObjectContext;

    //Getting all the CoreData contacts IDs to have something to compare
    NSArray *coreDataContactsIds = [ContactDAO getAllContactIdsInManagedObjectContext:context];

    for (NSDictionary *rec in coreDataContactsIds){
        NSNumber *recId = rec[@"record_id"];
        if (![unchangedRecords containsObject:recId]){
            //The unchanged record doesn't exist locally

            if (![updatedRecords containsObject:recId]){
                //The updated record doesn't exist locally

                if (![newRecords containsObject:recId]){
                    //The new record doesn't exist locally
                    //That means the ongoing record has been deleted from the addressbook,
                    //we also have to delete it locally

                    [ContactDAO deleteContactWithID:recId inManagedObjectContext:context];

                }

            }
        }

    }

    for (NSNumber *recId in updatedRecords){
        ABRecordID recordID = (ABRecordID)recId.intValue;
        ABRecordRef person = ABAddressBookGetPersonWithRecordID(addressbook, recordID);

        NSDictionary *personDict = [self getPersonDictionaryFromABRecordRef:person];
        if (personDict){
            [ContactDAO updateContactWithFirstName:personDict[@"firstName"] lastName:personDict[@"lastName"] compositeName:personDict[@"compositeName"] picture:personDict[@"picture"] phoneNumbers:personDict[@"phoneNumbers"] recordID:recId inManagedObjectContext:context];
        }
    }

    for (NSNumber *recId in newRecords){
        ABRecordID recordID = (ABRecordID)recId.intValue;
        ABRecordRef person = ABAddressBookGetPersonWithRecordID(addressbook, recordID);

        NSDictionary *personDict = [self getPersonDictionaryFromABRecordRef:person];
        if (personDict){
            [ContactDAO createContactWithFirstName:personDict[@"firstName"] lastName:personDict[@"lastName"] compositeName:personDict[@"compositeName"] picture:personDict[@"picture"] phoneNumbers:personDict[@"phoneNumbers"] recordID:recId inManagedObjectContext:context];
        }

    }

    NSError *dbError;
    [context save:&dbError];

    NSTimeInterval lastSyncTime = [[NSDate date]timeIntervalSince1970];

    [[NSUserDefaults standardUserDefaults]setObject:@(lastSyncTime) forKey:@"LastSyncTime"];
    completion(dbError);
}


- (NSDictionary*)getPersonDictionaryFromABRecordRef:(ABRecordRef)person{

    //Get name
    NSString * firstName, *lastName;
    firstName = CFBridgingRelease(ABRecordCopyValue(person, kABPersonFirstNameProperty));
    lastName  = CFBridgingRelease(ABRecordCopyValue(person, kABPersonLastNameProperty));

    firstName =  (firstName == nil) ? @"" : firstName;
    lastName  =  (lastName == nil)  ? @"" : lastName;
    NSString *compositeName;

    if ([firstName isEqualToString:@""] && [lastName isEqualToString:@""]){
        return nil;
    }

    if ([lastName isEqualToString:@""]){
        compositeName = [NSString stringWithFormat:@"%@", firstName];
    }
    if ([firstName isEqualToString:@""]){
        compositeName = [NSString stringWithFormat:@"%@", lastName];
    }
    if (![lastName isEqualToString:@""] && ![firstName isEqualToString:@""]){
        compositeName = [NSString stringWithFormat:@"%@ %@", firstName, lastName];
    }

    //Get picture
    CFDataRef imageData = ABPersonCopyImageData(person);
    NSData *data = CFBridgingRelease(imageData);

    //Get phone numbers
    NSMutableSet *phoneNumbers = [[NSMutableSet alloc]init];

    ABMultiValueRef phones = ABRecordCopyValue(person, kABPersonPhoneProperty);
    for(CFIndex i = 0; i < ABMultiValueGetCount(phones); i++) {

        CFStringRef str = ABMultiValueCopyValueAtIndex(phones, i);
        NSString *num = CFBridgingRelease(str);
        [phoneNumbers addObject:num];
        /*if(str)
         CFRelease(str);*/
    }

    //Save it in dictionary
    NSDictionary *personDict = [[NSDictionary alloc]initWithObjectsAndKeys:firstName, @"firstName",lastName , @"lastName",phoneNumbers,@"phoneNumbers", compositeName, @"compositeName", data, @"picture", nil];

     //Release everything.
     if(phones)
     CFRelease(phones);

    return personDict;

}
-(NSMutableArray*)获取所有记录,包括人:(CFArrayRef)所有人和地址簿:(ABAddressBookRef)地址簿{
NSMutableArray*newRecords=[[NSMutableArray alloc]init];
CFIndex nppeople=ABAddressBookGetPersonCount(地址簿);
for(int i=0;i- (NSMutableArray *)getAllRecordsWithPeople:(CFArrayRef)allPeople andAddressBook:(ABAddressBookRef)addressbook{
    NSMutableArray *newRecords = [[NSMutableArray alloc]init];
    CFIndex nPeople = ABAddressBookGetPersonCount(addressbook);

    for (int i=0;i < nPeople;i++){

        ABRecordRef ref = CFArrayGetValueAtIndex(allPeople,i);
        ABRecordID refId = ABRecordGetRecordID(ref);
        NSNumber *recId = [NSNumber numberWithInt:refId];
        [newRecords addObject:recId];
    }

    return newRecords;
}

- (void)getValidContactsFromAddressBookWithCompletionBlock:(void (^)(NSError *error))completion{

    ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, nil);

    __block BOOL accessGranted = NO;

    if (&ABAddressBookRequestAccessWithCompletion != NULL) {
        dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

        ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
            accessGranted = granted;
            dispatch_semaphore_signal(semaphore);
        });

        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    }

    if (accessGranted) {

        NSMutableArray *newRecords       = [[NSMutableArray alloc]init];
        NSMutableArray *updatedRecords   = [[NSMutableArray alloc]init];
        NSMutableArray *unchangedRecords = [[NSMutableArray alloc]init];

        CFArrayRef allPeople  = ABAddressBookCopyArrayOfAllPeople(addressBook);
        CFIndex nPeople       = ABAddressBookGetPersonCount(addressBook);

        //Checking the last time we updated
        NSTimeInterval lastSyncTime;
        if ([[NSUserDefaults standardUserDefaults]objectForKey:@"LastSyncTime"] == nil){
            //This is the first time we update.
            lastSyncTime = 0;
        }else{
            //Setting the last update in variable
            lastSyncTime = [[[NSUserDefaults standardUserDefaults]objectForKey:@"LastSyncTime"]doubleValue];
        }

        if (lastSyncTime == 0){
            //We have to insert everyone, this is the first time we do this.
            newRecords = [self getAllRecordsWithPeople:allPeople andAddressBook:addressBook];
        }else{
            //We have to manually compare everyone to see if something has changed.

            for (int i=0;i < nPeople;i++) {

                ABRecordRef ref = CFArrayGetValueAtIndex(allPeople,i);
                ABRecordID refId = ABRecordGetRecordID(ref);
                NSNumber *recId = @(refId);

                CFDateRef recordCreation = ABRecordCopyValue(ref, kABPersonCreationDateProperty);
                NSDate *recCreDate = (__bridge NSDate *)(recordCreation);
                NSTimeInterval creDateInterval = [recCreDate timeIntervalSince1970];

                if(creDateInterval > lastSyncTime){
                    //This object was created after my lastSync, this must be a new record
                    [newRecords addObject:recId];

                }else{

                    //Checking the last update of the given record
                    CFDateRef recordUpdate = ABRecordCopyValue(ref, kABPersonModificationDateProperty);
                    NSDate *recUpDate = (__bridge NSDate*)(recordUpdate);

                    if ([recUpDate timeIntervalSince1970] > lastSyncTime){
                        //The record was somehow updated since last time, we'll update it
                        [updatedRecords addObject:recId];

                    }else{
                        //The record wasn't updated nor created, it is therefore unchanged.
                        //We still need to keep it in a separate array to compare deleted contacts
                        [unchangedRecords addObject:recId];
                    }
                }

            }
            if(allPeople)
                CFRelease(allPeople);
        }

        [self manageNewContacts:newRecords updatedContacts:updatedRecords andUnchangedContacts:unchangedRecords inAddressBook:addressBook andBlock:^(NSError *error) {
            completion(error);
        }];
    }else{
        NSError *error = [NSError errorWithDomain:@"ABAccess access forbidden" code:403 userInfo:nil];
        completion(error);
    }
}

- (void)manageNewContacts:(NSMutableArray*)newRecords updatedContacts:(NSMutableArray*)updatedRecords andUnchangedContacts:(NSMutableArray*)unchangedRecords inAddressBook:(ABAddressBookRef)addressbook andBlock:(void (^)(NSError *error))completion{

    AppDelegate *app = [UIApplication sharedApplication].delegate;
    NSManagedObjectContext *context = app.managedObjectContext;

    //Getting all the CoreData contacts IDs to have something to compare
    NSArray *coreDataContactsIds = [ContactDAO getAllContactIdsInManagedObjectContext:context];

    for (NSDictionary *rec in coreDataContactsIds){
        NSNumber *recId = rec[@"record_id"];
        if (![unchangedRecords containsObject:recId]){
            //The unchanged record doesn't exist locally

            if (![updatedRecords containsObject:recId]){
                //The updated record doesn't exist locally

                if (![newRecords containsObject:recId]){
                    //The new record doesn't exist locally
                    //That means the ongoing record has been deleted from the addressbook,
                    //we also have to delete it locally

                    [ContactDAO deleteContactWithID:recId inManagedObjectContext:context];

                }

            }
        }

    }

    for (NSNumber *recId in updatedRecords){
        ABRecordID recordID = (ABRecordID)recId.intValue;
        ABRecordRef person = ABAddressBookGetPersonWithRecordID(addressbook, recordID);

        NSDictionary *personDict = [self getPersonDictionaryFromABRecordRef:person];
        if (personDict){
            [ContactDAO updateContactWithFirstName:personDict[@"firstName"] lastName:personDict[@"lastName"] compositeName:personDict[@"compositeName"] picture:personDict[@"picture"] phoneNumbers:personDict[@"phoneNumbers"] recordID:recId inManagedObjectContext:context];
        }
    }

    for (NSNumber *recId in newRecords){
        ABRecordID recordID = (ABRecordID)recId.intValue;
        ABRecordRef person = ABAddressBookGetPersonWithRecordID(addressbook, recordID);

        NSDictionary *personDict = [self getPersonDictionaryFromABRecordRef:person];
        if (personDict){
            [ContactDAO createContactWithFirstName:personDict[@"firstName"] lastName:personDict[@"lastName"] compositeName:personDict[@"compositeName"] picture:personDict[@"picture"] phoneNumbers:personDict[@"phoneNumbers"] recordID:recId inManagedObjectContext:context];
        }

    }

    NSError *dbError;
    [context save:&dbError];

    NSTimeInterval lastSyncTime = [[NSDate date]timeIntervalSince1970];

    [[NSUserDefaults standardUserDefaults]setObject:@(lastSyncTime) forKey:@"LastSyncTime"];
    completion(dbError);
}


- (NSDictionary*)getPersonDictionaryFromABRecordRef:(ABRecordRef)person{

    //Get name
    NSString * firstName, *lastName;
    firstName = CFBridgingRelease(ABRecordCopyValue(person, kABPersonFirstNameProperty));
    lastName  = CFBridgingRelease(ABRecordCopyValue(person, kABPersonLastNameProperty));

    firstName =  (firstName == nil) ? @"" : firstName;
    lastName  =  (lastName == nil)  ? @"" : lastName;
    NSString *compositeName;

    if ([firstName isEqualToString:@""] && [lastName isEqualToString:@""]){
        return nil;
    }

    if ([lastName isEqualToString:@""]){
        compositeName = [NSString stringWithFormat:@"%@", firstName];
    }
    if ([firstName isEqualToString:@""]){
        compositeName = [NSString stringWithFormat:@"%@", lastName];
    }
    if (![lastName isEqualToString:@""] && ![firstName isEqualToString:@""]){
        compositeName = [NSString stringWithFormat:@"%@ %@", firstName, lastName];
    }

    //Get picture
    CFDataRef imageData = ABPersonCopyImageData(person);
    NSData *data = CFBridgingRelease(imageData);

    //Get phone numbers
    NSMutableSet *phoneNumbers = [[NSMutableSet alloc]init];

    ABMultiValueRef phones = ABRecordCopyValue(person, kABPersonPhoneProperty);
    for(CFIndex i = 0; i < ABMultiValueGetCount(phones); i++) {

        CFStringRef str = ABMultiValueCopyValueAtIndex(phones, i);
        NSString *num = CFBridgingRelease(str);
        [phoneNumbers addObject:num];
        /*if(str)
         CFRelease(str);*/
    }

    //Save it in dictionary
    NSDictionary *personDict = [[NSDictionary alloc]initWithObjectsAndKeys:firstName, @"firstName",lastName , @"lastName",phoneNumbers,@"phoneNumbers", compositeName, @"compositeName", data, @"picture", nil];

     //Release everything.
     if(phones)
     CFRelease(phones);

    return personDict;

}