Hillegass Chapter 15 challenge

Discussion in 'Mac Programming' started by ehemmete, Feb 12, 2010.

  1. ehemmete macrumors newbie

    Joined:
    Feb 12, 2010
    #1
    I think this challenge is showing me that I am missing something fundamental about Cocoa/ObjC.

    In MyDocument.m I have added another button to the alert sheet and that works correctly. Then I added an else if to alertEnded that is getting triggered correctly when I click my new button. I know that I need to set expectedRaise to 0, but I just don't know who to tell.

    Following the delete option, I tried telling employeeController to setValue:0 forKey:mad:"expectedRaise". I've tried forKeyName:. I've tried the setNilValueForKey: method. I think that I want to use a keypath here, but I just can't reason out where to start and who to tell.

    I think part of it is that I don't quite understand the delete statement. Why are we passing remove nil and what is remove actually doing.

    Thanks! These forums have been very helpful up until now in my progress through the book.
     
  2. chown33 macrumors 604

    Joined:
    Aug 9, 2009
  3. ehemmete thread starter macrumors newbie

    Joined:
    Feb 12, 2010
    #3
    Alright, here it goes. In MyDocument.m I have the IBAction for a Delete button that should remove the selected entries from an array shown in a tableView.
    Code:
    - (IBAction)removeEmployee:(id)sender
    {
    	NSArray *selectedPeople = [employeeController selectedObjects];
    	NSAlert *alert = [NSAlert alertWithMessageText:@"Delete?"
    						       defaultButton:@"Delete"
    					  	    alternateButton:@"Cancel"
    						         otherButton:@"Keep, but no raise"
    				    informativeTextWithFormat:@"Do you really want to delete %d people?",
    					  [selectedPeople count]];
    	NSLog(@"Starting alert sheet");
    	[alert beginSheetModalForWindow:[tableView window]
    				  modalDelegate:self
    				  didEndSelector:@selector(alertEnded:code:context:)
    		 		       contextInfo:NULL];
    }
    
    When the user selects one of the buttons on the alert panel it will run the alertEnded:code:context method:
    Code:
    - (void)alertEnded:(NSAlert *)alert
    			  code:(int)choice
    		   context:(void *)v
    {
    	NSLog(@"Alert sheet ended");
    	if (choice == NSAlertDefaultReturn) {
    		[employeeController remove:nil];
    	} else if (choice == NSAlertOtherReturn) {
    		[employeeController setNilValueForKey:@"expectedRaise"];
    	}
    }
    
    Here is where I am having the problem. I can get to the else if correctly, but I'm not sure who to send a message to at this point. The delete (which works) talks to employeeController, so I have been trying that. employeeController is defined in MyDocument.h:
    Code:
    	IBOutlet NSArrayController *employeeController;
    
    When I run it as is and try to set the raise to 0, I get this error in the debugger:
    Code:
    [<NSArrayController 0x100443e50> setNilValueForKey]: could not set nil as the value for the key expectedRaise.
    Which I think is telling me that it isn't using the method that I wrote in Person.m.
    Code:
    -(void)setNilValueForKey:(NSString *)key
    {
    	if ([key isEqual:@"expectedRaise"]) {
    		[self setExpectedRaise:0.0];
    	} else {
    		[super setNilValueForKey:key];
    	}
    }
    I feel like I should be able to use a key path to tell the elements in the array to set the expectedRaise value to 0, but I can't figure out how to get there.
     
  4. crackpip macrumors regular

    Joined:
    Jul 23, 2002
    #4
    The program is getting into the else if branch, but you're sending a setNilValueForKey to the employeeController. employeeController doesn't have an expectedRaise instance variable (ivar). So get the selected rows from the employeeController, which will return an NSArray with the selected instances of your Person class. You then need to create a loop which sets expected raise to zero in each instance.

    crackpip
     
  5. ehemmete thread starter macrumors newbie

    Joined:
    Feb 12, 2010
    #5
    Thank you, thank you

    That was enough to me push in the right direction (I think, at least it works now).
    Code:
    - (void)alertEnded:(NSAlert *)alert
    			  code:(int)choice
    		   context:(void *)v
    {
    	NSLog(@"Alert sheet ended");
    	if (choice == NSAlertDefaultReturn) {
    		[employeeController remove:nil];
    	} else if (choice == NSAlertOtherReturn) {
    		NSArray *selectedPeople = [employeeController selectedObjects];
    		for (Person *p in selectedPeople)
    		{
    			[p setNilValueForKey:@"expectedRaise"];
    		}
    	}
    }
     
  6. DavidPotter macrumors newbie

    Joined:
    Aug 14, 2010
    Location:
    Bothell, WA
    #6
    Not sure why you need to call setNilValueForKey. Is there something I'm missing? I'm simply setting the value in the Person object, like so, which seems to work:

    Code:
    - (void) alertEnded: (NSAlert *) alert
                   code: (int) choice
                context: (void *) vContext
    {
        NSLog(@"Alert sheet ended");
        if (choice == NSAlertDefaultReturn)
        {
            [employeeController remove: nil];
        }
        else if (choice == NSAlertOtherReturn)
        {
            NSArray * employeesCollection = [employeeController selectedObjects];
            for (Person * employee in employeesCollection)
            {
                employee.expectedRaise = 0.0;
            }
        }
    }
     

Share This Page