Challenge


#1

Rather lost but still working on it :wink: However, should createNewEmployee by createEmployee (on page 157)?

Should the outlet be to the ‘Cars’ icon in the Objects list? The link I mage from from Referencing Outlet (Table Cell View content > Cars) I’m getting an error 'Unsupported Configuration Outlet ‘content’ of ‘Cars’ is connected ‘Table Cell View’, an invalid destination (Object maybe repeated at run time.)


#2

Worked it out with the help of the solution :blush:
Was also able to set condition on new entry (as well as date). Interesting combination of no code (before challenge) and added code for new functionality (after challenge)


#3

I had to use the sample solution too :blush: But I have to say that the description of the challenge was very misleading for me.
I thought we should try to select the whole Make/Model column not the cell for editing, so I looked for
things like “selectColumnIndexes:byExtendingSelection:” and run into a dead end :frowning:

cu
Vertex


#4

pharmpk - thanks for the tip on createNewEmployee:; I’ve added it to the errata.

If either of you have any additional feedback, with the benefit of having figured it out now, as far as what made this challenge particularly difficult, I’d be interested to hear it. Vertex, it sounds like the wording “select the Make/Model” might better have been “begin editing the Make/Model”?

Thanks,

Adam


#5

Yes, Adam, that would be better.

cu
Vertex


#6

After hours of working on this, I broke down and looked at the solution. Now I know why I was confused. Tell me why this statement is correct [quote] Hint: You will need to add an outlet to CarArrayController. [/quote] It seems to me, the outlet(s) in the solution are in MyDocument. Even after looking at the solution, I’m still somewhat confused. I so wish Apple had not dropped the Java / Cocoa bridge.


#7

In the example solution to this challenge, the outlet to CarArrayController is used within createCar: to more easily create the Car entity and so forth. I’m not sure I understand your question, however - is there some reason you think there should not be an outlet?

Don’t get too discouraged – this is one of the more challenging topics in the book, in particular because so much of it is “magic”. There are a lot of smarts hidden inside Core Data and NSArrayController and it can be tricky to get a handle on how they work together.

Adam


#8

[quote=“AdamPreble”]In the example solution to this challenge, the outlet to CarArrayController is used within createCar: to more easily create the Car entity and so forth. I’m not sure I understand your question, however - is there some reason you think there should not be an outlet?

Don’t get too discouraged – this is one of the more challenging topics in the book, in particular because so much of it is “magic”. There are a lot of smarts hidden inside Core Data and NSArrayController and it can be tricky to get a handle on how they work together.

Adam[/quote]

Adam, Thanks, I’m not getting too discouraged, just frustrated and anxious for the mental map of how Cocoa works and it’s unique terminology to firm up in my head. To answer the question. When you said “add and outlet to CarArrayController,” I first assumed that what you meant was to define an outlet in CarArrayController.h. After looking back at this chapter and previous ones, I now see what was probably meant is to connect the NSArrayController Cars (because in terms I’m familiar with, Cars “IS A” NSArrayController) to an instance variable (AKA pointer to an NSArrayController; AKA outlet) in the Document object controller. In this case, that’s MyDocument.h. That physically can be done by either control dragging from the Cars Dock icon to MyDocument.h, or by defining the NSArrayController outlet *carsController first, then right click on Cars in the Dock and under Referencing Outlets and drag from the circle next to carsController to File’s Owner. Of course, that was only one of the steps required. The createCar method is about 50% clear. I trust that it will all make sense at some point.


#9

Ahh, I see what you mean now. We’ll have to look at making that more clear.

Adam


#10

For the first time a challenge was actually challenging :smiley: (generally the challenges are not very challenging, and with the hints are way too easy, but that’s for another thread :wink: ).

My first idea for this challenge was to add code to the newObject method in my NSArrayController subclass. But that didn’t work out so well, and then I did as in the RaiseMan app: putting a newCar method into the document class.

But wouldn’t code like this belong more logical in the controller class, and also is it all possible to use the newObject method for this?


#11

In this case, as in many document-based apps, the document class is actually a controller class: it acts as the window controller. So it’s pretty sensible to put createCar: in the document class. The document class is offloading some of its controller responsibilities to the array controller.

As far as using newObject for this, I’m guessing you mean hooking into the array controller and receiving some sort of notification of a new object having been created? Or perhaps overriding newObject? Technically I suppose it could work but then the CarArrayController becomes less reusable as it is more tied to the UI (unless you are careful to keep the table interaction optional).

Adam


#12

Hi all

I’ve struggled through the chapter ! Yeah. But I sure don’t understand more than maybe 50%.
( Which I don’t consider to be too bad, actually ) I cheated and looked at the solution to the challenge

One question; if I can compose it properly.
– For RaiseMan, we have a class named Person, and so we create a person object to add to the control array
with the line
// Create the object
Person *p = [employeeController newObject];

In the CarLot, we have made an “entity” named “Car” that is sort of our “class”, but
we don’t use “Car” as a class to make a new object. We use
id p = [carsController newObject];

Just a little explanation about these might help me understand a little better.
THANKS !

Judy


#13

Judy,

That’s a pretty accurate description. I think I’m missing your actual question, however?

To say a little more about it: in Core Data, if we don’t create an NSManagedObject subclass (which we will do in Chapter 32), the return value of -newObject is an NSManagedObject. NSManagedObject is KVC-compliant for the attributes we’ve added to it, such as datePurchased, so we can write [p valueForKey:@“datePurchased”] to get the date value, or set the date value with [p setValue:now forKey:@“datePurchased”].

Adam


#14

I had exactly this same issue, as it’s sorta what the literal translation to what we should do. Still working on this challenge…


#15

I finally grabbed the solution code and saw that I had made the same mistake as others.

All my code was correct, but I had added it to CarArrayController.

Perhaps a clearer wording on this would be that you need to ‘connect an outlet to CarArrayController’, rather than ‘add an outlet to CarArrayController’. Since you don’t actually ‘add an outlet to CarArrayController’! :slight_smile:


#16

I notice that binding the Add button to the add method of Cars (array controller) was replaced by binding the createCar: method to File’s Owner.
I assume that the add method in Cars received actions panel called the newObject method in the NSArrayController (or CarArrayController) class.
Is createCar (or create) a protocol in the NSPersistentDocument class? I assume that binding the Add button to this method of myDocument:NSPersistentDocument (File’s Owner) overrides (cancels) the previous binding to the add method of the NSArrayController class.
Somehow the newObject method of CarArrayController is still called, despite this introduction of the createCar: method? This is confusing to me.

Also, doesn’t the addition of IBOutlets and IBActions in this challenge disturb the architecture of the program – the separation of model/data and interface?


#17

I’ve been having a bit of trouble with this one – but I hadn’t gone with the createNewEmployee example verbatim, more used it as a loose guide. It seemed that there should be a way, in the spirit of the data object model and binding lesson of this chapter to get this one done without going back to the manual way of doing things.

This either almost works, or is way off base, and I’m not sure which. Everything is bound properly (I think), but instead of the createCar mentioned elsewhere, I have the following, bound to the Add button:

- (IBAction)addCar:(id)sender
{    
    // find the index of the object just added
    NSUInteger row = [tableView selectedRow];
    
    NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:row];
    
    // insert a new row      ## making a copy of the previous row?!? ##FIX
    [tableView insertRowsAtIndexes:indexSet
                     withAnimation:NSTableViewAnimationSlideDown];
    
    // begin the edit in the first column
    NSLog(@"starting edit of new car in row %lu", row);
    
    [tableView editColumn:0
                      row:row
                withEvent:nil
                   select:YES];
}

On running the app, a new row gets created, everything shifts down, and the new row is in edit mode, but the new row is already filled with the data of the previous row. I still haven’t wrapped my head round Apple’s documentation, so I can’t quite tell if the problem is that I’m passing something incorrectly or just plain trying to do it wrong…
It just seemed that, since the tableView already exists as a proxy object and it already has methods, I could maybe use that instead of creating new objects?

Also, assuming this could be made to work at all, since the existing functionality in the tableView & arrayController bindings and the NSManagedObjectModel are magically handling the undo stack, wouldn’t this forego having to do that manually as well? (I can’t tell, since the duplicate rows are colliding right now.)

I’m going to dig into this a bit more, but if someone could chime in and tell me whether I’m chasing wild geese, I’d really appreciate it!

Thanks!
Sylvania


#18

I solved the challenge by adding an action to MyDocument.m that I called (IBAction)addCar:(id)sender and it works.

But why does it say in the book: “Hint: You will need to add an outlet to CarArrayController”. I got it working without adding anything to CarArrayController:

[code]@interface CarArrayController : NSArrayController

@end[/code]


#19

[quote=“rohdester”]For the first time a challenge was actually challenging :smiley: (generally the challenges are not very challenging, and with the hints are way too easy, but that’s for another thread :wink: ).

My first idea for this challenge was to add code to the newObject method in my NSArrayController subclass. But that didn’t work out so well, and then I did as in the RaiseMan app: putting a newCar method into the document class.

But wouldn’t code like this belong more logical in the controller class, and also is it all possible to use the newObject method for this?[/quote]

That was my thought as well: we’re setting values for datePurchased in the newObject method, why not work a little on the table there: add an outlet to the table view to the CarArrayController class and you’re in busines, or so I thought…
By rewriting the add-button, as in the solution, it feels as if you are ‘breaking in’ on the Core Data proces and are rewiring the whole setup. Now you have to work on the undoManager again even. Is it possible to make it work in the newObject method for instance?
Marijn


#20

[quote=“MarijnD”]
That was my thought as well: we’re setting values for datePurchased in the newObject method, why not work a little on the table there: add an outlet to the table view to the CarArrayController class and you’re in busines, or so I thought…
By rewriting the add-button, as in the solution, it feels as if you are ‘breaking in’ on the Core Data proces and are rewiring the whole setup. Now you have to work on the undoManager again even. Is it possible to make it work in the newObject method for instance?
Marijn[/quote]
I was thinking along these lines, as well, but I was thinking that I would have to override carArrayController(->NSArrayController->NSObjectController)'s add: or addObject: method to include the code to put the new object into edit mode. Is that a possible solution, or was I thinking along too complicated lines?