Problems with the challenge "Keep, but no raise"


#1

Hi
I tried to complete the challenge at the end of chapter 15, and I think I’ve got it, well, sort of. It does what it is supposed to do. It doesn’t delete the employees and it resets their raises to 0…
But whenever I have clicked on my keep-button, and then click on the add button, Xcode gives me an error.
I don’t know what I have done wrong…
My thoughts on how to solve the challenge:
[ul]
Find the method that checks user input from the alert sheet
Create an array of the selected objects
Iterate through the employees array
Whenever the array of the selected objects are the same as the array controllers selected objects: set peoples raises to zero.
[/ul]
However everything did’t turn out the way I had hoped…

MyDocument.m
// This is the method that is being called when the user clicks a button on the alert sheet after first clicking the remove 
// button
- (void)alertEnded:(NSAlert *)alert code:(int)choice context:(void *)v {
	NSLog(@"Alert sheet ended");
	// If the user chose "Delete," tell the array controller to
	// delete the people
	if ( choice == NSAlertDefaultReturn ) {
		// The argument to remove: is ignored
		// The array controller will delete the selected objects
		[employeeController remove:nil];
	} else if ( choice == NSAlertOtherReturn ) {
		NSLog(@"Keep 'em!");
		id noRaise = @"0";
		NSArray *peeps = [employeeController selectedObjects];
		for ( employees in peeps ) {
			if ( peeps == [employeeController selectedObjects] ) {
			[peeps setValue:noRaise forKey:@"expectedRaise"];
			}
		}
		[peeps release]; // I don't know if this is necessary
	}
}

I hope there’s someone who can help me, I’m kind of lost at this point
Thank you in advance
Timm


#2

[quote=“kaspth”]Hi
I tried to complete the challenge at the end of chapter 15, and I think I’ve got it, well, sort of. It does what it is supposed to do. It doesn’t delete the employees and it resets their raises to 0…
But whenever I have clicked on my keep-button, and then click on the add button, Xcode gives me an error.
[/quote]

What’s the error?

that sounds quite complicated…

my thoughts how to solve this:

first we need to know which employees raises have to bet set to zero, that’s easy because we’re “abusing” the removeEmployee-method and we know how to get all the people that are selected (via employeeController’s selectedObjects), this returns an NSArray with Person-objects (which can be iterated with fast iteration) and all we have to do now is use some Key-Value magic to set the expectedRaise-value to 0.0

well let’s go through your code…

id noRaise = @“0”; – seems like you’re a fan of “dynamic typing” and well I guess it’s fine because the kvc-magic knows how to convert from NSString (the @"" should make it an NSString I suppose) to float… OTOH the compiler will catch errors more easily when you use real objects (like NSNumber, see Chapter 7, Page 117)

NSArray *peeps = [employeeController selectedObjects]; – good, the NSArray with all the employees we need

for ( employees in peeps ) { – hm, honestly I thought we have to use something like “for (Person *p in peeps)” but you’re using the the class-variable NSMutableArray *employees and I have no idea what this does… (heck I’m even amazed the compiler just takes it without a warning/error)

if ( peeps == [employeeController selectedObjects] ) – Why you’re doing this check? I bet it’s always true because you just “pointed” peeps to the array returned by employeeController’s selectedObjects…

[peeps setValue:noRaise forKey:@“expectedRaise”]; – hm that’s interesting, that should make the whole for-loop senseless and you know what, it even works…

[peeps release]; // I don’t know if this is necessary – urgs… did you retain the array returned from employeeController’s selectedObjects? I don’t think so and I guess that’s why you’re seeing an error because everything’s deallocated, so be sure to delete this

[quote=“kaspth”]
I hope there’s someone who can help me, I’m kind of lost at this point
Thank you in advance
Timm[/quote]

I hope I did

while we’re at it, someone knows how to translate “Keep, but no raise” into French? :slight_smile:


#3

For the translation try http://translate.google.com/#.


#4

Thank you very much! I really appreciate it!
I’m now error free (so far).

Actually today, before I saw your reply, I went in the code and deleted some of the less-insightful things I did (the if-statement, the release of p).
The code I ended up with (the above) was really a lot of “compromised” code. The list of thoughts in the above post wasn’t really how I wanted to go about this challenge at first, but then there were several things I didn’t know how to get or do. E.g. I tried several ways to set the value of expectedRaise without luck, using kvc wasn’t my first line of thought, but eventually I ended up using it, because, well… it worked :slight_smile:

I do not, however, get what you mean about being a fan of “dynamic typing,” I did not want to use id, I tried using:
float noRaise = 0; (I also tried to use NSNumber *noRaise = 0; but no luck there either)
But then the compiler said it couldn’t set nil as a value for the key. So I ended up with another line of “compromised” code.

Well, anyway thank you for your kind reply. It definitely helped me out and I learned something new as well.


#5

I’m not sure why your loop is working at all. I believe peeps is a NSArray and employees is a NSMutableArray. So peeps will either be equivalent to or a subset of employees. i.e. you will have one to all of the records in the tableView selected.

As for my final solution, I just used the @synthesized setter for each person in the selectedPeople (peeps).
Here is the solution I came up with:

[code]- (void)alertEnded:(NSAlert *)alert
code:(int)choice
context:(void *)v
{
NSLog(@“Alert sheet ended”);

// if (choice == NSAlertDefaultReturn)
// {
// [employeeController remove:nil];
// }

switch (choice) 
{
	case NSAlertDefaultReturn:
		[employeeController remove:nil];
		break;
	case NSAlertOtherReturn:
	{
		NSArray *selectedPeople = [employeeController selectedObjects];
		for (Person *person in selectedPeople)
		{
			[person setExpectedRaise:0.0];
		}
		break;
	}
	default:
		break;
}

}[/code]


#6

My code looked almost like yours, but with some of kaspth ideas I changed mine to

// ...
	} else if (returnCode == NSAlertOtherReturn) {
		NSArray *selectedEmployees = [employeeController selectedObjects];
		[selectedEmployees setValue:[NSNumber numberWithFloat:0.0] forKey:@"expectedRaise"];
	}

PS: translating with yahoo’s babelfish or google translate sucks because you’ll always get something which makes native speakers rofl IMHO, so Aaron please, in the next edition provide a French translation for “Keep, but no raise” because my otherwise localized RaiseMan feels incomplete without it somehow :slight_smile:


#7

Cool. Hadn’t thought of that; definitely more efficient.


#8

This is so cool!
I feel like I’m part of a community where we’re all sharing and receiving. I’m glad that my code or ideas actually proved to be useful to someone, yours certainly were to me.


#9

Hello,
Please excuse my bad english, I’m French.

I have a problem with the correction of the Raise Man Challenge.

My code works fine,

[code]
-(void)alertEnded:(NSAlert )alert
code:(int)choice
context:(void
)v
{
NSLog(@“Alert sheet ended”);
//If the user chose "Delete, tell the array controller to delete the people
if(choice==NSAlertDefaultReturn) {
//the argument to remove: is ignored
//The array controller will delete the selected objects
[employeesController remove:nil];

} else if (choice == NSAlertOtherReturn) {
	
	for(Person * e in [employeesController selectedObjects])
		[e setExpectedRaise:0.0];

}

}[/code]

I don’t understand why you need to reload the view as the table view is bound to the array controller.

The table view is an observer of the array and is notified when the expectedRaise is modified by setExpectedRaise: am I right ?
I just want to be sure, that I’m not missing something.
Thank you.

By the way, the french translation for “Keep but no Raise” is “Garder mais ne pas augmenter”