Here's what I came up with. Think it's doing what it should but always happy to get feedback on what could be better.

AddressBook.h
//
// AddressBook.h
// prog10
//
// Created by Mark Reid on 20/04/2010.
// Copyright 2010 __MyCompanyName__. All rights reserved.
//
#import <Foundation/NSArray.h>
#import "AddressCard.h"
@interface AddressBook : NSObject <NSMutableCopying> {
NSString *bookName;
NSMutableArray *book;
}
@property (assign, nonatomic) NSString *bookName;
@property (assign, nonatomic) NSMutableArray *book;
-(id) initWithName: (NSString *) name;
-(void) addCard: (AddressCard *) theCard;
-(void) removeCard: (AddressCard *) theCard;
-(AddressCard *) lookup: (NSString *) theName;
-(int) entries;
-(void) list;
-(void) sort;
-(void) dealloc;
@end
AddressBook.m
//
// AddressBook.m
// prog10
//
// Created by Mark Reid on 20/04/2010.
// Copyright 2010 __MyCompanyName__. All rights reserved.
//
#import "AddressBook.h"
@implementation AddressBook
@synthesize bookName, book;
-(id) mutableCopyWithZone:(NSZone *)zone
{
AddressBook *newAddressBook = [[AddressBook allocWithZone: zone] init];
newAddressBook.bookName = [self.bookName retain];
// newAddressBook.book = [self.book copy];
newAddressBook.book = [[NSMutableArray alloc] init];
for (AddressCard *theCard in self.book) {
AddressCard *newCard = [theCard copy];
[newAddressBook addCard: newCard];
[newCard release];
}
return newAddressBook;
}
// set up the AddressBook's name and an empty book
-(id) initWithName:(NSString *)name
{
self = [super init];
if (self) {
bookName = [[NSString alloc] initWithString: name];
book = [[NSMutableArray alloc] init];
}
return self;
}
-(void) addCard:(AddressCard *)theCard
{
[book addObject: theCard];
}
-(void) removeCard:(AddressCard *)theCard
{
[book removeObjectIdenticalTo: theCard];
}
// lookup address card by name - assumes an exact match
-(AddressCard *) lookup: (NSString *) theName
{
for (AddressCard *nextCard in book)
if ([[nextCard name] caseInsensitiveCompare: theName] == NSOrderedSame)
return nextCard;
return nil;
}
-(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(@"==================================================");
}
-(void) sort
{
[book sortUsingSelector: @selector(compareNames:)];
}
-(void) dealloc
{
[bookName release];
[book release];
[super dealloc];
}
@end
AddressCard.h
//
// AddressCard.h
// prog8
//
// Created by Mark Reid on 20/04/2010.
// Copyright 2010 __MyCompanyName__. All rights reserved.
//
#import <Foundation/NSObject.h>
#import <Foundation/NSString.h>
@interface AddressCard : NSObject <NSCopying> {
NSString *name;
NSString *email;
}
@property (copy, nonatomic) NSString *name, *email;
-(void) setName:(NSString *) theName andEmail: (NSString *) theEmail;
-(NSComparisonResult) compareNames: (id) element;
-(void) print;
-(void) dealloc;
@end
AddressCard.m
//
// AddressCard.m
// prog8
//
// Created by Mark Reid on 20/04/2010.
// Copyright 2010 __MyCompanyName__. All rights reserved.
//
#import "AddressCard.h"
@implementation AddressCard
@synthesize name, email;
-(id) copyWithZone:(NSZone *)zone
{
AddressCard *theCard = [[AddressCard alloc] init];
theCard.name = [self.name retain];
theCard.email = [self.email retain];
return theCard;
}
-(void) setName:(NSString *) theName andEmail: (NSString *) theEmail
{
self.name = theName;
self.email = theEmail;
}
-(NSComparisonResult) compareNames: (id) element
{
return [name compare: [element name]];
}
-(void) print
{
NSLog(@"=====================================");
NSLog(@"| |");
NSLog(@"| %-31s |", [name UTF8String]);
NSLog(@"| %-31s |", [email UTF8String]);
NSLog(@"| |");
NSLog(@"| |");
NSLog(@"| O O |");
NSLog(@"| |");
NSLog(@"=====================================");
}
-(void) dealloc
{
[name release];
[email release];
[super dealloc];
}
@end
ex1.m
// Implement a copy method for the AddressBook class according to the NSCopying protocol.
#import <Foundation/Foundation.h>
#import "AddressBook.h"
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
AddressBook *myAddressBook = [[AddressBook alloc] initWithName: @"My Address Book"];
AddressBook *theOtherAddressBook;
AddressCard *card1 = [[AddressCard alloc] init];
AddressCard *card2 = [[AddressCard alloc] init];
AddressCard *card3 = [[AddressCard alloc] init];
[card1 setName: @"Nick Fury" andEmail: @"nick@shield.gov"];
[card2 setName: @"Pepper Potts" andEmail: @"pepper@starkindusties.com"];
[card3 setName: @"Tony Stark" andEmail: @"tony@starkindustires.com"];
// Populate the address book after creating it and the cards to fill it with
[myAddressBook addCard: card1];
[myAddressBook addCard: card2];
[myAddressBook addCard: card3];
// Create a mutable copy of the address book
theOtherAddressBook = [myAddressBook mutableCopy];
// Change the original address books name and remove a card
myAddressBook.bookName = @"Original Address Book";
[myAddressBook removeCard: card2];
[card1 setName: @"Another Name" andEmail: @"another@email.com"];
// Print the two address books and compare the results, the second address book should contain unaltered data
[myAddressBook list];
[theOtherAddressBook list];
[myAddressBook release];
[theOtherAddressBook release];
[card1 release];
[card2 release];
[card3 release];
[pool drain];
return 0;
}