Amazon.com Widgets Attempted answer to exercise 15-2
Welcome, Guest. Please login or register.
Did you miss your activation email?
June 19, 2013, 10:11:59 PM
Home Help Search chat Login Register   
News: Read this please.The Great Kangaroo Escape Looking for reviews of the 4th ed on Amazon!   Twitter:  @skochan
                     

+  Official Forum for Programming in Objective-C (the iPhone Programming Language) - Stephen Kochan
|-+  Old Stuff
| |-+  Answers to Exercises
| | |-+  Chapter 15
| | | |-+  Attempted answer to exercise 15-2
Pages: [1]   Go Down
Print
Author Topic: Attempted answer to exercise 15-2  (Read 1322 times)
mdeh
Full Member
***
Posts: 166






« on: February 05, 2009, 09:17:08 PM »

AddressBook.h
Code: (Objective-C)
#import "AddressCard.h"
#import <Foundation/NSArray.h>



@interface AddressBook : NSObject {

NSString * bookName;
NSMutableArray * book;

}

-(id) initWithName: (NSString *) theName;
-(void) addCard: (AddressCard *) theCard;
-(int) entries;
-(void) list;
-(void) dealloc;

-(AddressCard *) lookUp: (NSString *) theName;
-(void) removeCard: (AddressCard *) aCard;
-(void) sort;

@end

AddressBook.m
Code: (Objective-C)
#import "AddressBook.h"



@implementation AddressBook

-(id) initWithName: (NSString *) theName
{
self = [super init];

if ( self)
{
bookName =[ [ NSString alloc] initWithString: theName];
book = [ [ NSMutableArray alloc] init];

}
return self;
}

-(void) addCard: (AddressCard *) theCard
{
[book addObject: theCard];
}

-(int) entries
{
return book.count;
}

-(AddressCard *) lookUp: (NSString *) theName;
{
NSRange found;
for ( AddressCard *theCard in book){


/* if ( [theCard.name  caseInsensitiveCompare: theName ] == NSOrderedSame ) */


found = [theCard.name rangeOfString: theName];
if (found.location != NSNotFound)
return theCard;

}


return nil;
}

-(void) removeCard: (AddressCard *) aCard
{
[ book removeObjectIdenticalTo: aCard];
}

-(void) sort
{
[book sortUsingSelector: @selector(compareNames:)];
}


-(void) list
{


NSLog(@"******* AddressBook: %@   ********", bookName);

for ( AddressCard * theCard in book)
{
NSLog(@" Name:%-20s   %-32s", [theCard.name UTF8String], [theCard.email UTF8String] );
}


}

-(void) dealloc
{
[bookName release];
[book release];
[super dealloc];
}


@end

AddressCard.h
Code: (Objective-C)
#import <Foundation/NSObject.h>
#import <Foundation/NSString.h>


@interface AddressCard : NSObject {
NSString *name;
NSString *email;
}

@property(copy, nonatomic) NSString *name, *email;

-(void) setName: (NSString *) n;
-(void) setEmail: (NSString *) e;
-(void) setName: (NSString *) theName andEmail: ( NSString *) theEmail;

-(NSString *) name;
-(NSString *) email;

-(void) print;
-(NSComparisonResult) compareNames: (AddressCard *) element;


@end

AddressCard.m
Code: (Objective-C)
#import "AddressCard.h"


@implementation AddressCard

@synthesize name, email;

-(void) setName: (NSString *) n
{
[name release];
name = [ [ NSString alloc] initWithString: n];
}

-(void) setEmail: (NSString *) e;
{
[email release];
email = [ [ NSString alloc] initWithString: e];
}

-(void) setName: (NSString *) theName andEmail: ( NSString *) theEmail
{
[self setName: theName];
[self setEmail: theEmail];
}


-(NSString *) name
{
return name;
}

-(NSString *) email
{
return email;
}


-(NSComparisonResult) compareNames: (AddressCard *) element
{
return [ [element name] compare: name ];
}



-(void) print
{
NSLog(@"-------------------------------");
NSLog(@"|                               |");
NSLog(@"|%-31s|", [name UTF8String]);
NSLog(@"|%-31s|", [email UTF8String]);
NSLog(@"|                               |");
NSLog(@"|                               |");
NSLog(@"|                               |");
NSLog(@"--------------------------------");
}

-(void) dealloc
{
[name release];
[email release];
[super dealloc];
}


@end

main.m  **test program**
Code: (Objective-C)
#import "AddressBook.h"

int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
AddressBook * book = [ [ AddressBook alloc] initWithName: @"Exercise 15-2"];
AddressCard * card1 = [ [ AddressCard alloc] init];
AddressCard * card2 = [ [ AddressCard alloc] init];
AddressCard * card3 = [ [ AddressCard alloc] init];
AddressCard * card4 = [ [ AddressCard alloc] init];
AddressCard * card5 = [ [ AddressCard alloc] init];
AddressCard * found;

[card1 setName: @"Harry Potter" andEmail: @"hp@hogwarts.witchery"];
[card2 setName: @"Bat Man" andEmail: @"bats@batcave.com"];
[card3 setName: @"Invis Woman" andEmail: @"nosee@wu.gov"];
[card4 setName: @"Dick Cheney" andEmail: @"exwh1@dontcomeback.com"];
[card5 setName: @"Lord Nelson" andEmail: @"hmsvictory@trafalgar.sea"];

[book addCard: card1];
[book addCard: card2];
[book addCard: card3];
[book addCard: card4];
[book addCard: card5];

[book list];

NSLog(@"Looking up \"Harry\"");
found = [book lookUp: @"Harry"];
if ( found != nil)
[found print];
else
NSLog(@"not found");


NSLog(@"Looking up \"Woman\"");
found = [book lookUp: @"Woman"];
if ( found != nil)
[found print];
else
NSLog(@"not found");

NSLog(@"Looking up \"elso\"");
found = [book lookUp: @"elso"];
if ( found != nil)
[found print];
else
NSLog(@"not found");

         NSLog(@"Looking up \"George\"");
found = [book lookUp: @"George"];
if ( found != nil)
[found print];
else
NSLog(@"not found");



[card1 release];
[card2 release];
[card3 release];
[card4 release];
[card5 release];
[book release];
    [pool drain];
    return 0;
}


« Last Edit: February 08, 2009, 12:11:19 PM by mdeh » Logged
sir
Full Member
***
Posts: 118


Email




« Reply #1 on: April 03, 2009, 08:08:20 PM »

With this code of mdeh, how does this search out a match of part of a string in a search?  First of all, where does "name" come from in theCard.name?  Does the argument of the string just test to see if a range can be found in the accessor string to see if there is a match?


Code: (Objective-C)
-(AddressCard *) lookUp: (NSString *) theName;
{
NSRange found;
for ( AddressCard *theCard in book){


/* if ( [theCard.name  caseInsensitiveCompare: theName ] == NSOrderedSame ) */


found = [theCard.name rangeOfString: theName];
if (found.location != NSNotFound)
return theCard;

}


return nil;
}
Logged
gbacchus
Newbie
*
Posts: 1


Email




« Reply #2 on: May 28, 2009, 09:22:41 PM »

Also, this lookup method doesn't search the email addresses in your address book. 

I am having a different problem with this one.  My lookup method is as follows:

-(NSMutableArray *) lookup: (NSString *)  theName
{

NSMutableArray *results;
NSRange substr1, substr2;

results = [[NSMutableArray alloc] init];

for (AddressCard *nextCard in book){
     substr1 = [nextCard.name rangeOfString: theName];
     substr2 = [nextCard.email rangeOfString: theName];

     if ((substr1.location != NSNotFound) || (substr2.location != NSNotFound))
          [results addObject: nextCard];
     }
return results;
}


This method works just fine except for one thing: it is case dependent.  Does anyone have an idea of how to do this where you can search for StEvE and still get the lookup method to find Steve's card?

Also, I am a little confused as to whether I have a memory leak here with the results array.  In my main routine I define an array called searchResults and assign it as follows:

searchResults = [myBook lookup: @"steve"];

I was thinking that as long as I release searchResults then I don't have to worry about the "results" array that is allocated in the lookup method.  Am I correct here, or do I have a memory leak?

One more thing... how do I post my code like I keep seeing other people do? 

Logged
skochan
Administrator
Hero Member
*****
Posts: 3109







« Reply #3 on: May 29, 2009, 04:34:19 AM »

Quote
This method works just fine except for one thing: it is case dependent.  Does anyone have an idea of how to do this where you can search for StEvE and still get the lookup method to find Steve's card?

Look at the rangeOfString:options: method.

Quote
Also, I am a little confused as to whether I have a memory leak here with the results array.  In my main routine I define an array called searchResults nd assign it as follows:

searchResults = [myBook lookup: @"steve"];

I was thinking that as long as I release searchResults then I don't have to worry about the "results" array that is allocated in the lookup method.  Am I correct here, or do I have a memory leak?

No you don't. searchResults does in fact reference the array you allocated in your lookup: method, so if you release searchResults you will be okay.

Quote
One more thing... how do I post my code like I keep seeing other people do? 

Select your code and then press the button that shows the # from the Add BBC tags: menu bar.

Cheers,

Steve Kochan
« Last Edit: May 29, 2009, 04:37:35 AM by skochan » Logged
webwrx
Newbie
*
Posts: 41






« Reply #4 on: August 22, 2009, 05:08:45 PM »

I originally came up with this lowercaseString conversion to handle the case insensitive business... but now I have since discovered the more elegant rangeOfString:options: approach.  Cheesy

Code: (Objective-C)
-(AddressCard *) lookupPartial: (NSString *) partName
{
NSRange substr;
for (AddressCard *nextCard in book) {
substr = [[[nextCard name] lowercaseString] rangeOfString: [partName lowercaseString]];
if (substr.location != NSNotFound)
return nextCard;
}
return nil;
}


I think some people might be reading too much into exercise 2. It's not asking for multiple results, just a small modification to the existing lookup: method that can handle a partial match.  The fun stuff is in exercise 3.  Tongue

Ben
Logged
bluesman99
Newbie
*
Posts: 1


Email




« Reply #5 on: August 23, 2009, 11:30:31 AM »

Gbacchus's code is on the right track -- nice and clean.  I have modified rangeOfString (in AddressBook.m) to solve the case sensitive problem.  Thanks to Stephen for pointing out the rangeOfString options.  I think "NSCaseInsensitiveSearch" does the trick.  Everything seems to be working now.  

Question.. I would like to split the "mySearch" method (in AddressBook.m) into two methods: one to search and one to print.  I can't seem to get my head around passing the new array ("found") back to the main program, then, calling another method to print it.  Any help would be appreciated.

Note that I added a console prompt (scanf) in the main program.  This way, the search string is dynamic rather than hard-coded. Great for quickly validating the code.

AddressCard.h
Code: (Objective-C)
#import <Foundation/Foundation.h>

@interface AddressCard: NSObject
{
NSString *name;
NSString *email;
}

@property (copy, nonatomic) NSString *name, *email;

//  Method to set  name and email at same time
-(void) setName: (NSString *) theName andEmail: (NSString *) theEmail;

@end

AddressCard.m
Code: (Objective-C)
#import "AddressCard.h"

@implementation AddressCard

@synthesize name, email;

// Method to set both name and email at once
-(void) setName: (NSString *) theName andEmail: (NSString *) theEmail
{
self.name = theName;
self.email = theEmail;
}

@end

AddressBook.h
Code: (Objective-C)
#import "AddressCard.h"
#import <Foundation/NSArray.h>

@interface AddressBook : NSObject {

NSString * bookName;
NSMutableArray * book;
}

-(id) initWithName: (NSString *) theName;
-(void) addCard: (AddressCard *) theCard;
-(void) list;
-(void) dealloc;
-(AddressCard *) mySearch: (NSString *) theName;

@end

AddressBook.m
Code: (Objective-C)
#import "AddressBook.h"

@implementation AddressBook

//--------------------------------------------
-(id) initWithName: (NSString *) theName
{
self = [super init];

if ( self)
{
bookName =[ [ NSString alloc] initWithString: theName];
book = [ [ NSMutableArray alloc] init];

}
return self;
}

//--------------------------------------
-(void) addCard: (AddressCard *) theCard
{
[book addObject: theCard];
}

// ------------------------------------
-(AddressCard *) mySearch: (NSString *) theName;
{
NSMutableArray *found;
NSRange substr1, substr2;

found = [[NSMutableArray alloc] init];

for (AddressCard *theCard in book){
substr1 = [theCard.name rangeOfString: theName options:NSCaseInsensitiveSearch];
substr2 = [theCard.email rangeOfString: theName options:NSCaseInsensitiveSearch];

if ((substr1.location != NSNotFound) || (substr2.location != NSNotFound))
[found addObject: theCard];
}

//Print "found" array to console
NSLog(@" ");
NSLog(@"******* Search Results  ********");
NSLog(@"Search for: %@", theName);
for (AddressCard * theCard in found)
{
NSLog(@" Name:%-20s   %-32s", [theCard.name UTF8String], [theCard.email UTF8String] );
}

if ([found count] == 0)
NSLog(@"Sorry, no records found in search.");

NSLog(@"*****************************");

return nil;
}

//------------------------------------------------
-(void) list
{

NSLog(@"******* AddressBook: %@   ********", bookName);

for (AddressCard * theCard in book)
{
NSLog(@" Name:%-20s   %-32s", [theCard.name UTF8String], [theCard.email UTF8String] );
}

}

//-----------------------------------------------------
-(void) dealloc
{
[bookName release];
[book release];
[super dealloc];
}

@end

Main.m
Code: (Objective-C)
#import "AddressBook.h"

int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

// Create AddressBook class pointer
AddressBook * book = [ [ AddressBook alloc] initWithName: @"Exersise 15-2"];

// Create AddressCard class pointers
AddressCard * card1 = [ [ AddressCard alloc] init];
AddressCard * card2 = [ [ AddressCard alloc] init];
AddressCard * card3 = [ [ AddressCard alloc] init];
AddressCard * card4 = [ [ AddressCard alloc] init];
AddressCard * card5 = [ [ AddressCard alloc] init];

// Set AddressCard variables
[card1 setName: @"George Washington" andEmail: @"george.washington@whitehouse.gov"];
[card2 setName: @"John Adams" andEmail: @"john.adams@whitehouse.gov"];
[card3 setName: @"Thomas Jefferson" andEmail: @"thomas.jefferson@whitehouse.gov"];
[card4 setName: @"James Madison" andEmail: @"james.madison@whitehouse.gov"];
[card5 setName: @"James Monroe" andEmail: @"james.monroe@whitehouse.gov"];

// Add cards (data) to book
[book addCard: card1];
[book addCard: card2];
[book addCard: card3];
[book addCard: card4];
[book addCard: card5];

// Call list method
[book list];

//prompt for user input
char name[100];
NSString *mySearchString;
printf("What name are you looking for? Hint: Enter first few letters.");
scanf("%s", &name);
mySearchString = [NSString stringWithCString: name encoding: NSASCIIStringEncoding];

// Search for string in book
[book mySearch: mySearchString];

//Memory release
[card1 release];
[card2 release];
[card3 release];
[card4 release];
[card5 release];
[book release];
    [pool drain];
    return 0;
}

« Last Edit: August 23, 2009, 08:14:48 PM by bluesman99 » Logged
Pages: [1]   Go Up
Print
Jump to:  



Login with username, password and session length

Powered by MySQL Powered by PHP Powered by SMF 1.1.11 | SMF © 2006-2009, Simple Machines LLC Valid XHTML 1.0! Valid CSS!
Entire forum contents (c) 2009 classroomM.com. All rights reserved.