你的位置:首页 > 操作系统

[操作系统]用OC实现实现中等难度通讯录详解


用OC实现中等难度通讯录。需求:

     1、定义联系人类Contact。实例变量:姓名(拼音,⾸字⺟大写)、性别、电话号码、 住址、分组名称、年龄。⽅法:⾃定义初始化方法或便利构造器方法、显⽰联系人信息

     2、在main.m中定义字典,分组管理所有联系人。分组名为26个大写的英文字母。

     3、可以添加联系⼈对象,如果姓名或电话号码为空,添加失败。添加联系⼈到匹配的分组。

     4、获取某个分组名称下所有联系人,并且按照姓名升序排列。

     5、从通讯录中根据电话号码搜索联系人。

     6、获取所有⼥性的联系人,并且按照年龄的降序排列。

     7、根据姓名删除某个联系人。

     8、删除某个分组的全部联系人。

 

Contact.h的声明部分:

1、在Contact.h文件中实例变量:姓名、性别、电话号码、住址、分组名称, 年龄. 方法:自定义初始化方法或便利构造器方法、显示联系人信息.

 1 @interface Contact : NSObject 2 { 3   NSString *_name; 4   NSString *_gender; 5   NSString *_phoneNumber; 6   NSString *_address; 7   NSString *_groupName; 8   NSInteger _age; 9 }10 11 // 实例变量的setter和getter方法12 - (void)setName:(NSString *)name;13 - (NSString *)name;14 15 - (void)setGender:(NSString *)gender;16 - (NSString *)gender;17 18 - (void)setPhoneNumber:(NSString *)phoneNumber;19 - (NSString *)phoneNumber;20 21 - (void)setAddress:(NSString *)address;22 - (NSString *)address;23 24 - (void)setGroupName:(NSString *)groupName;25 - (NSString *)groupName;26 27 - (void)setAge:(NSInteger)age;28 - (NSInteger)age;29 30 // 自定义初始化方法31 - (id)initWithName:(NSString *)name gender:(NSString *)gender phoneNumber:(NSString *)phoneNumber address:(NSString *)address groupName:(NSString *)groupName age:(NSInteger)age;32 33 // 遍历构造器方法34 + (id)contactWithName:(NSString *)name gender:(NSString *)gender phoneNumber:(NSString *)phoneNumber address:(NSString *)address groupName:(NSString *)groupName age:(NSInteger)age;35 36 @end

2.Contact.m实现文件代码

 1 @implementation Contact 2 // 自定义初始化方法 3 - (id)initWithName:(NSString *)name gender:(NSString *)gender phoneNumber:(NSString *)phoneNumber address:(NSString *)address groupName:(NSString *)groupName age:(NSInteger)age { 4    5   // 判断父类有没有完全初始化 6   if (self = [super init]) { 7     _name = name; 8     _gender = gender; 9     _phoneNumber = phoneNumber;10     _address = address;11     _groupName = groupName;12     _age = age;13   }14   return self;15 }16 17 18 // 遍历构造器方法19 + (id)contactWithName:(NSString *)name gender:(NSString *)gender phoneNumber:(NSString *)phoneNumber address:(NSString *)address groupName:(NSString *)groupName age:(NSInteger)age {20   21   return [[Contact alloc] initWithName:name gender:gender phoneNumber:phoneNumber address:address groupName:groupName age:age];22 }23 24 25 - (void)setName:(NSString *)name {26   _name = name;27 }28 - (NSString *)name {29   return _name;30 }31 32 - (void)setGender:(NSString *)gender {33   _gender = gender;34 }35 - (NSString *)gender {36   return _gender;37 }38 39 - (void)setPhoneNumber:(NSString *)phoneNumber {40   _phoneNumber = phoneNumber;41 }42 - (NSString *)phoneNumber {43   return _phoneNumber;44 }45 46 - (void)setAddress:(NSString *)address {47   _address = address;48 }49 - (NSString *)address {50   return _address;51 }52 53 - (void)setGroupName:(NSString *)groupName {54   _groupName = groupName;55 }56 - (NSString *)groupName {57   return _groupName;58 }59 60 - (void)setAge:(NSInteger)age {61   _age = age;62 }63 - (NSInteger)age {64   return _age;65 }66 67 68 // 重写description方法(这个方法在无需声明,程序运行时,系统会自动走这个方法)69 - (NSString *)description70 {71   return [NSString stringWithFormat:@"%@ - %@ - %@ - %@ - %@ - %ld", _name, _gender, _phoneNumber, _address, _groupName, _age];72 }73 74 @end

3.创建AddressBook并定义实例变量_manger来管理通讯录的联系人

AddressBook.h文件

 1 #import <Foundation/Foundation.h> 2 @class Contact;  //注意:在使用前需要在AddressBook.h文件中用@class引入Contact 3  4 @interface AddressBook : NSObject 5 { 6    7   NSMutableDictionary *_manger; 8 } 9 10 - (void)setManger:(NSMutableDictionary *)manger;11 - (NSMutableDictionary *)manger;12 13 // 添加联系人的方法14 - (void)addContact:(Contact *)contact;15 16 // 展示所有联系人信息的方法17 - (void)showAllContact;18 19 // 获取某个分组下所有的联系人,并按姓名升序20 - (NSMutableArray *)getAllContactByGroupName:(NSString *)groupName;21 22 // 根据电话号码查找联系人23 - (Contact *)findContactByPhoneNumber:(NSString *)phoneNumber;24 25 // 根据性别获取联系人,并按年龄排序26 - (NSMutableArray *)getAllContactByGender:(NSString *)gender;27 28 // 根据姓名删除联系人的方法29 - (void)removeContactByName:(NSString *)name;30 31 // 删除某个分组全部联系人32 - (void)removeContactByGroupName:(NSString *)groupName;33 34 @end

 

下面,就是各个方法的实现了,且看AddressBook.m文件

 1 #import "AddressBook.h" 2 #import "Contact.h" 3 @implementation AddressBook 4  5 - (instancetype)init 6 { 7   self = [super init]; 8   if (self) { 9     // 初始化字典 10     _manger = [NSMutableDictionary dictionaryWithCapacity:0]; 11   } 12   return self; 13 } 14  15  16 // _manger的setter和getter方法 17 - (void)setManger:(NSMutableDictionary *)manger { 18   _manger = manger; 19 } 20 - (NSMutableDictionary *)manger { 21   return _manger; 22 } 23  24  25 // 添加联系人的方法 26 - (void)addContact:(Contact *)contact { 27  28   //如果姓名或电话号码为空,添加失败 29   if (0 == contact.name.length || 0 == contact.phoneNumber.length || nil == contact.name || nil == contact.phoneNumber) { 30     NSLog(@"姓名或电话号码为空,添加失败!请重新输入"); 31     return; 32   }else{ 33      34     // 否则,可以添加联系人到分组.首先取出字典中key值对应的数组(也就是取出分组名构成的数组) 35     NSMutableArray *group = [_manger objectForKey:contact.groupName]; 36      37     // 如果group为空,说明key值不存在,也就是说此时字典中没有分组名.则初始化数组,并添加联系人 38     if (nil == group) { 39       group = [NSMutableArray arrayWithCapacity:0]; // 初始化 40       [group addObject:contact]; // 将联系人添加到group中 41     }else{   // 如果group不为空,说明key值存在,有这个分组.则直接添加联系人到该分组 42       [group addObject:contact]; 43     } 44      45     // 修改字典中的键值对(由于新增了联系人,所以要修改字典的键值对) 46     [_manger setObject:group forKey:contact.groupName]; 47   } 48 } 49  50  51 // 展示所有联系人信息的方法 52 - (void)showAllContact { 53    54   for (NSString *key in _manger) { 55     NSString *value = [_manger objectForKey:key]; 56     NSLog(@"%@ = %@", key, value); 57   } 58 } 59  60  61 // 获取某个分组下所有的联系人,并按姓名升序 62 - (NSMutableArray *)getAllContactByGroupName:(NSString *)groupName { 63  64   // 根据key值返回key值对应的value值,也就是将根据传入的分组名将该分组中所有的联系人保存到一个数组中 65   NSMutableArray *group = [_manger objectForKey:groupName]; 66    67   // 如果group为空,说明分组不存在 68   if (group == nil) { 69     NSLog(@"提示:您搜索的分组不存在"); 70     return nil; 71   } 72    73   // 如果该分组存在,那么就对group里面的联系人按姓名排序 74   NSInteger count = group.count; // 用双层for循环需要知道group的个数 75    76   for (int i = 0; i < count - 1; i++) { 77     for (int j = 0; j < count - i - 1; j++) { 78        79       // 由于数组名加下标不能点出人的name属性,需要将group[j] group[j + 1]取出来用Contact对象进行操作 80       Contact *p1 = group[j]; 81       Contact *p2 = group[j + 1]; 82        83       if ([p1.name compare:p2.name] == NSOrderedDescending) { 84         // 如果p1.name比p2.name大,则交换位置 85         [group exchangeObjectAtIndex:j withObjectAtIndex:j + 1]; 86       } 87     } 88   } 89   return group; 90 } 91  92  93 // 根据电话号码查找联系人 94 - (Contact *)findContactByPhoneNumber:(NSString *)phoneNumber { 95  96   // 首先遍历key值(分组名),取出各分组下对应的联系人信息. 遍历字典,默认的就是遍历key值 97   for (NSString *key in _manger) { 98      99     NSMutableArray *group = [_manger objectForKey:key];100     101     // 再遍历group数组,查找与传入的电话号码相同的联系人,并输出联系人102     for (Contact *p in group) {103       104       if ([p.phoneNumber isEqualToString:phoneNumber]) {105         return p;106       }107     }108   }109   // 如果没有就返回空110   return nil;111 }112 113 114 // 根据性别获取联系人,并按年龄排序115 - (NSMutableArray *)getAllContactByGender:(NSString *)gender {116 117   // 定义一个可变数组,用于存储找到的联系人118   NSMutableArray *genderArray = [NSMutableArray arrayWithCapacity:0];119   120   // 先通过遍历key值(遍历分组名),取出各分组下对应的联系人信息121   for (NSArray *key in _manger) {122     NSMutableArray *group = [_manger objectForKey:key];123     124     // 再遍历group数组,根据联系人的性别判断是否需要添加到genderGroup数组中125     for (Contact *p in group) {126       127       // 将遍历到与传入的性别一致的联系人添加到genderGroup数组中128       if ([p.gender isEqualToString:gender]) {129         [genderArray addObject:p];130       }131     }132   }133   134   // 排序135   // 首先获取数组中元素的个数136   NSInteger count = genderArray.count;137   138   // 根据年龄排序139   for (int i = 0; i < count - 1; i++) {140     141     for (int j = 0; j < count - i - 1; j++) {142       143       // 同样滴,数组名加下标不能点出人的姓名,将其取出来用Contact对象操作144       Contact *p1 = genderArray[j];145       Contact *p2 = genderArray[j + 1];146       147       if (p1.age > p2.age) {148         [genderArray exchangeObjectAtIndex:j withObjectAtIndex:j + 1];149       }150     }151   }152   // 返回排好序的数组153   return genderArray;154 }155 156 157 // 根据姓名删除联系人的方法158 - (void)removeContactByName:(NSString *)name {159   160   // 先取出姓名的首字母, 并转为大写,将其全部放到一个数组里面存储161   NSString *string = [[name substringToIndex:1] capitalizedString];162   163   for (int i = 0; i < [[_manger valueForKey:string]count]; i++) {164     // 遍历存储姓名首字母大写的数组,并判断是否与传入的姓名的首字母是否一致165     166     if ([[[[_manger valueForKey:string] objectAtIndex:i]name] isEqualToString:name]) {167       // 删除坐标为i,姓名为name的对象168       [[_manger valueForKey:string] removeObjectAtIndex:i];169     }170   }171 }172 173 174 // 删除某个分组全部联系人175 - (void)removeContactByGroupName:(NSString *)groupName {176 177   // 删除了key值对应的value值即可178   [_manger removeObjectForKey:groupName];179 }180 181 @end

最后,在main函数中=:

1)首先引入头文件

#import "Contact.h"

#import "AddressBook.h"

#import "Color.h"

2)创建几个联系人,依次调用各方法

  // 创建几个联系人对象  Contact *p1 = [Contact contactWithName:@"ZhangSan" gender:@"men" phoneNumber:@"10086" address:@"NewYork" groupName:@"Z" age:26];  Contact *p2 = [Contact contactWithName:@"WuYaoYao" gender:@"women" phoneNumber:@"10087" address:@"BeiJing" groupName:@"W" age:27];  Contact *p3 = [Contact contactWithName:@"ZhengXi" gender:@"women" phoneNumber:@"10088" address:@"ZhengZhou" groupName:@"Z" age:28];  Contact *p4 = [Contact contactWithName:@"HaoBing" gender:@"men" phoneNumber:@"10089" address:@"KunMing" groupName:@"H" age:22];    // 创建一个AddressBook对象来管理联系人  AddressBook *addressBook = [[AddressBook alloc] init];    // 调用添加联系人的方法  [addressBook addContact:p1];  [addressBook addContact:p2];  [addressBook addContact:p3];  [addressBook addContact:p4];    // 调用展示联系人所有信息的方法  [addressBook showAllContact];    // 调用获取某个分组下所有联系人并按姓名排序的方法  NSMutableArray *groupNameContact = [addressBook getAllContactByGroupName:@"Z"];  NSLog(@"%@", groupNameContact);    // 调用根据电话号码获取联系人的方法  Contact *finder = [addressBook findContactByPhoneNumber:@"10086"];  NSLog(@"%@", finder);    // 调用根据性别获取联系人并按年龄排序的方法  NSMutableArray *genderArray = [addressBook getAllContactByGender:@"women"];  NSLog(@"%@", genderArray);    // 调用根据姓名删除联系人的方法  [addressBook removeContactByName:@"HaoBing"];  [addressBook showAllContact];    // 调用删除某个分组下的所有联系人的方法  [addressBook removeContactByGroupName:@"Z"];  [addressBook showAllContact];

 以上就是这个题目的全部解析.

此外,为了优化代码,我们在这里引入几个知识点:

1. 在展示联系人信息的时候,我们采用的是forin这种方法来实现.此外,由于所有联系人都放在一个字典里面,我们同样可以采用NSDictionary下的一个方法实现遍历:

 [dic enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {

        <#code#>

    }];

    // 第一个参数 字典中的key值

    // 第二个参数 字典中key值对应的value值

    // 第三个参数 枚举结束的条件

  enumerateKeysAndObjectsUsingBlock方法其实际只有一个参数block:^(id key, id obj, BOOL *stop) ,这个block携带了三个参数,执行这个方法时,会把Dictionary里面的key值和value值每次一组地传递给block,依次遍历dictionary并把里面所有的key值和value值,将其一组一组地展示出来.在这里,我们要展示所有联系人的信息,那么我们同样可以利用这种方法,上代码:

1 // 展示所有联系人的信息2 - (void)showAllContact {3 4   [_manger enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {5     NSLog(@"%@ = %@", key, obj);6   }];7 }

再例如:

//定义了这样一个字典,要求遍历字典输出
NSDictionary *dic = @{@"1":@"a", @"2":@"b", @"3":@"c"}; [dic enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { NSLog(@"%@ - %@", key, obj); *stop = YES; }];

不止是字典有这种遍历的方法,NSArrray同样具有类似的遍历方法 

     [array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {

       code

     }];

    // 第一个参数obj 是枚举得到的数组元素

    // 第二个参数idx 枚举出数组元素的下标

    // 第三个参数 枚举停止的条件

    // 该方法的执行步骤是 枚举取出数组的元素给obj,同时将其对应的下标给 idx ,直到遇到停止条件stop

  值得注意的是:由于这种方法的前面一个参数默认的是 id 类型, 有时候我们在后面可能需要点出obj的实例变量时无法点出来,这就需要我们将 id 类型修改为想要的类型;

  例如:

// 定义一个数组,要求找出@"3"并输出
NSArray *array = @[@"1", @"2", @"3", @"4", @"5"];[array enumerateObjectsUsingBlock:^(NSString * obj, NSUInteger idx, BOOL * stop) { if ([obj isEqualToString:@"3"]) { NSLog(@"%@ %lu", obj, idx); *stop = YES; // 如果 *stop = YES ,就会提前结束这个快速枚举. *stop默认是NO } }];

 

2.在涉及到排序的题目中,我们通常采用的是双层for循环,这样就需要我们知道数组中元素的count,这里列举一种不需要count的方法:

sortUsingComparator:

    [arr sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {

        code

    }];

    // 参数 obj1 和 obj2 是数组中两个相邻的元素

    // 此方法的排序方式是根据block块中返回值是NSOrderedDescending对应的判断条件的为准,让相邻的两个元素交换位置

 例如:

  NSArray *arr = @[@"2", @"1", @"6", @"8", @"5", @"9", @"3"];  NSArray *sortArray2 = [arr sortedArrayUsingComparator:^NSComparisonResult(NSString *obj1, NSString *obj2) {        if (obj1.intValue > obj2.intValue) {            return NSOrderedDescending;          }else if(obj1.intValue < obj2.intValue){            return NSOrderedAscending;          }else{            return NSOrderedSame;    }  }];    NSLog(@"%@", sortArray2);

file:///Users/lanouhn/Library/Containers/com.tencent.qq/Data/Library/Application%20Support/QQ/Users/1792427320/QQ/Temp.db/1308F9FD-0A97-43F7-87B2-2A264B459012.png

在通讯录练习中,我们用这种方法来实现 获取分组下所有联系人,并按姓名大小排序的功能:

// 获取分组下所有联系人,并按姓名大小排序- (NSMutableArray *)sortAllContactByGroupName:(NSString *)groupName {  NSMutableArray *group = [_manger objectForKey:groupName];    if (group == nil) {    NSLog(@"您搜索的分组下没有联系人");    return nil;  }  [group sortUsingComparator:^NSComparisonResult(Contact *obj1, Contact *obj2) {    if ([obj1.name compare:obj2.name] == NSOrderedDescending) {      return NSOrderedDescending;    }else if([obj1.name compare:obj2.name] == NSOrderedAscending){      return NSOrderedAscending;    }else{      return NSOrderedSame;    }  }];  return group;}