3.AddressBook类
AddressBook类存储地址薄的名字和一个AddressCard的集合,将这个集合存储在一个数组对象中。要先创建一个地址薄,然后要向其中增加AddressCard,计算地址薄的记录数,列出地址薄的内容,还要搜索地址薄,删除记录,编辑现有记录,将记录排序,甚至复制记录。
AddressBook.h接口文件
#import <Foundation/Foundation.h>
#import "AddressCard.h"
@interface AddressBook : NSObject
@property (nonatomic, copy) NSString *bookName;
@property (nonatomic, strong) NSMutableArray *book;
-(id) initWithName:(NSString *) name;
-(void) addCard: (AddressCard *) theCard;
-(int) entries;
-(void) list;
@end
AddressBook.m实现文件#import "AddressBook.h"
@implementation AddressBook
@synthesize bookName,book;
// 设置AddressBook的名称和一个空的AddressBook
-(id) initWithName:(NSString *)name
{
self = [super init];
if (self) {
bookName = [NSStringstringWithString:name];
book = [NSMutableArrayarray];
}
return self;
}
-(id) init
{
return [selfinitWithName:@"NOName"];
}
-(void) addCard:(AddressCard *)theCard
{
[book addObject: theCard];
}
-(int) entries{
return [book count];
}
-(void ) list
{
NSLog(@"=======Contents of:%@=======",bookName);
for (AddressCard *theCardin book ) {
NSLog(@"%-20s %-32s",[theCard.nameUTF8String],[theCard.email UTF8String]);
}
NSLog(@"================================");
}
定义的initWithName:方法返回一个id对象,而不是AddressBook对象。如果创建一个AddressBook的子类,那么initWithName:消息的接收者(以及返回值)不是AddressBook对象,它的类型使子类的类型。因此将返回类型定义为id类型。覆写init方法能够保证:如果某人在调用alloc方法之后调用init方法,仍然可以正确的创建地址薄,而且默认的名字是“NOName”。这里的initWithName:方法是我们指定的初始化方法,目的是确保init方法会调用它。
addCard:方法将AddressCard对象作为参数,把它添加到地址薄中。
count方法返回数组元素的个数。entris方法中使用这个方法返回地址薄中的地址卡片的数目。
4.快速枚举
list方法的for循环展示一个快速枚举技术:
for (AddressCard *theCard in book ) {
NSLog(@"%-20s %-32s",[theCard.name UTF8String],[theCard.email UTF8String]);
}
在这里对book数组中每个元素序列使用名为快速枚举技术,它的语法非常简洁:首先定义一个能偶保留数组中每一个元素的变量(AddressCard *theCard)。使用关键字in,然后列出数组名称。当使用for循环时,它会先数组中的每一个元素赋给指定的变量,并执行循环体。然后,将第二个元素赋给变量,并执行循环体。这样一直下去,直到数组的所有元素都已经赋给变量,这样数组的每个元素都执行循环体。注意,如果theCard已经定义为AddressCard对象,那么for循环可以变得更加简洁,语句如下:
for (theCard in book)
5.在地址薄中查询某人
现在增加一个查找方法,名称为lookup:,把需要查找的姓名作为参数。这个方法会搜索整个地址薄进行匹配,如果匹配成功,则返回这个记录,如果电话薄中不存在需要查找的姓名,则返回nil。
-(AddressCard *) lookup: (NSString *) theName
{
for (AddressCard *nextCard in book)
if ( [nextCard.name caseInsensitiveCompare: theName] == NSOrderedSame )
return nextCard;
return nil;
}
这个方法非常简单,更好的方法可以实现部分匹配和多重匹配,比如:记录Steve Kochan、Fred stevens和steven levy都可以满足
[myBook lookup:@"steve"];
的匹配条件。有可能存在多重匹配,所以有效的方法是创建一个包含所有匹配的数组,将它返回给方法的调用者,例如:
matches = [myBook lookup:@"steve"];
6.从地址薄中删除某人
可以构造一个removeCard:方法,将指定的AddressCard从地址薄中删除,将AddressCard作为参数。
-(void) removeCard: (AddressCard *) theCard
{
[book removeObjectIdenticalTo: theCard];
}
关于什么是同一个对象,系统认为是对象位于内存中的同一个位置。所以,当两个包含相同信息的地址卡片对象处于不同的内存单元时,removeObjectIdenticalTo:方法并不会把他们视为同一个对象。所以removeObjectIdenticalTo:根据对象的地址判断两个对象是否相等。与其不同的是方法removeObject:方法根据isEqual消息判断两个对象是否相等。使用自己的方法处理相等的对象更加合理,可以编写自己的isEqual:方法。当使用removeObject:方法时,系统会调自动针对数组中的每一个调用isEqual:方法对两个元素进行比较。这个例子中,因为地址薄包含AddressCard对象作为成员,必须将isEqual方法添加到类中覆盖从NSObject继承的方法,这样可以如何确定等同性。
isEqual:方法可以这样写:
-(BOOL) isEqual: (AddressCard *) theCard
{
if ( [name isEqualToString: theCard.name] == YES && [email isEqualToString: theCard.email] ==YES)
return YES;
else
return NO;
}
要注意NSArray类中containsObject:和indexOfObject:方法都依赖isEqual:策略来决定两个对象是否相等。
AddressBook.h接口文件
#import <Foundation/Foundation.h>
#import "AddressCard.h"
@interface AddressBook : NSObject
@property (nonatomic, copy) NSString *bookName;
@property (nonatomic, strong) NSMutableArray *book;
-(id) initWithName:(NSString *) name;
-(void) addCard: (AddressCard *) theCard;
-(int) entries;
-(void) list;
-(AddressCard *) lookup: (NSString *)theName;
-(void) removeCard:(AddressCard *) theCard;
-(void) sort;
@end
AddressBook.m实现文件
#import "AddressBook.h"
@implementation AddressBook
@synthesize bookName,book;
// 设置AddressBook的名称和一个空的AddressBook
-(id) initWithName:(NSString *)name
{
self = [super init];
if (self) {
bookName = [NSString stringWithString:name];
book = [NSMutableArray array];
}
return self;
}
-(id) init
{
return [self initWithName:@"NOName"];
}
-(void) addCard:(AddressCard *)theCard
{
[book addObject: theCard];
}
-(int) entries{
return [book count];
}
-(void ) list
{
NSLog(@"=======Contents of:%@=======",bookName);
for (AddressCard *theCard in book ) {
NSLog(@"%-20s %-32s",[theCard.name UTF8String],[theCard.email UTF8String]);
}
NSLog(@"================================");
}
-(AddressCard *) lookup:(NSString *)theName
{
for(AddressCard *nextCard in book)
if ([nextCard.name caseInsensitiveCompare:theName] ==NSOrderedSame) {
return nextCard;
}
return nil;
}
-(void) removeCard:(AddressCard *)theCard
{
[book removeObjectIdenticalTo: theCard];
}
/*-(void) sort
{
[book sortUsingSelector:@selector(compareNames:)];
}*/
-(void) sort
{
[book sortUsingComparator: ^(id obj1, id obj2) {
return [[obj1 name] compare:[obj2 name]];
}];
}
@end