I'm setting up an edit window for a player to edit his user data. I've got all of the fields on the edit form bound to the appropriate Core Data entity (via an NSArrayController), and I've got an awakeFromNib method installed to handle calling the record, but I'm not sure what to put inside the method to get the record to display.
Ultimately, my goal with this is to set it up so that the application checks whether an entry exists for the user, and create one for him if there's no entry in the table.
You should look at using a NSObjectController or NSArrayController rather than binding directly to the NSManagedObject. The controllers work properly with bindings and your data will display nicely and changes you make will be propagated via the controller to your NSManagedObject.
You can set the object used by the controller in your awakeFromNib. On NSArrayController use the setSelectionIndex:(NSUInteger) index message and then to avoid empty selection send it the setAvoidEmptySelection:TRUE message
Hope that helps.
Related
Every tutorial I read about data binding / NSArrayController told to set the Mode and the Keys in the Object Controller (Attributes Inspector) for the data model class I use. Why do I have to do this?
In my sample application I create all objects in code and add them to the array controller in code too. The program still works fine without any settings in the Object Controller. I use the NSCollectionView to present my data.
To answer the question in the subject, the Object Controller section lets you determine what the array controller is controlling. In your screenshot the array controller is controlling objects of a Person class. But the array controller can also control a Core Data entity. That's what the Mode menu is for. The keys are pieces of the object/entity the array controller is controlling.
The reason the tutorials tell you to set the mode and keys is they are demonstrating using NSArrayController with Cocoa bindings. You must set the mode and keys so you can bind the array controller to the collection view in Interface Builder and have the collection view display relevant data from the array controller. If you are writing code to do all the NSArrayController work and not using Cocoa bindings, you can avoid setting the mode and keys.
So, i have a simple table view and my column 'Name' is bound to NSArrayController. The NSArrayController is defined with Entity type and is going to hold Person objects. I have checked "Prepares content" in the XIB file. In my application, i create and insert a managed object called "Network". This class has delegate methods that handle data incoming from the network. When my updateNotificationMethod is called, i create my Person managed object and insert it into the managed object context of "Network".
The above works like charm and i am able to display the names in the table view without any issues. However, if i handle the notifications in a thread that has a new managedObjectContext and i handle NSManagedObjectContextDidSaveNotification in my main thread to merge the changes into my main managed object context, then i don't see any updates in my table view.
Shouldn't the NSArrayController be aware of the new managed objects merged and display those?
Any ideas on what i am missing here?
If you create "Network" on the main context and optain to it with [network objectID] in your background thread make sure you do a save before entering the background thread. Otherwise the objectID of "Network" will be temporary and lead at the end not to the correct object.
Everything else looks fine to me.
I have a standard Table View with the default settings inside my main nib. I use an Array Controller and Bindings for dealing with the data that the table view should show to the users. I already achieved that the "add" button inserts the new row and sets the first column to editing mode so the users can type their text immediately. My problem is i can't detect when the editing is over and i should save the new values. I couldn't find any delegate method and/or any notification for this purpose. I searched the internet and i couldn't find anything useful. I'm not even sure that i'm doing it right, i didn't add any specific thing, i just use the standard double click editing that the table view offers for each cell.
Any help is much appreciated.
Thanks in advance!
If you have everything hooked up with bindings, you shouldn't need to save the data until you exit the program. When the array controller's add: method is called, the new record is added to the controller's arranged objects, and the array holding your data is also updated. So, you only need to save the array when your app closes.
However, if you wish to save the data after every edit, you can detect the end of the editing with the delegate method controlTextDidEndEditing:. You will get a notification after each column is finished editing (make sure to make the class where you implement this method the delegate of the table view).
I'm working on a application with the this interface (sorry the language is Dutch):
http://www.flickr.com/photos/pluueer/5756159100/
The Add function (incl. the four NSTextFields) under the NSTableView are to moved to a sheet someday, but for now this is fine. I've set up bindings according to a tutorial (http://cocoadevcentral.com/articles/000080.php), but the tutorial doesn't supply how to add rows in the way I want to (just adds an empty row which you need to edit in the NSTableView).
I've got a connection between the 'Voeg toe' (Dutch for 'Add') button and the Array Controller. But after clicking I get the message:
2011-05-28 23:37:56.149 Hop Calc[4345:a0f] -[__NSPlaceholderDictionary initWithObjects:forKeys:]: number of objects (0) not equal to number of keys (4)
It makes sense, because I've not implemented anything for adding rows, but I just don't know how.
"Add a row to the table" is the wrong way to think of it. Your table represents a collection and a controller provides the information to the table, mediating between the table (view) and the collection (model). Since you mentioned bindings, the collection is likely managed by an NSArrayController. So you want to add a new object (of the kind your array controller manages) to the array controller's content array.
Simplest way: Connect the Add button to the -add: action of the NSArrayController. It'll add an empty row.
If you want more control, connect the Add button to your own custom action in some controller. That action will create an instance of whatever's represented by your array controller, prepopulate it (or whatever you want to do), then, using an outlet it holds to your NSArrayController, will call the array controller's -addObject: method to add the object (the possibly a -rearrangeObjects call to get the array controller to re-sort its contents).
The method applicationDidFinishLaunching:, is called in the app delegate prior to the loading of a Core Data entity into a table created with the "Core Data Entity" tool in the Interface Builder Library.
I have a custom view (with controller) that charts data based on the selected Core Data entity. When I launch my application, the top entry in the table of Core Data entities automatically is selected and other text fields bound to properties of that entity are populated with the correct data. I need to send a message to the custom view controller to redraw the custom view after the data is loaded at application launch.
Where should I put the code to send the message to the custom view controller? Is there a delegate method similar to applicationDidFinishLaunching: that receives a notification after the core data entity is loaded at launch?
It took me a while to figure this out since I'm relatively new to Cocoa. The appropriate documentation is here: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreData/Articles/cdBindings.html
If the "automatically prepares
content" flag (see, for example,
setAutomaticallyPreparesContent:) is
set for a controller, the controller's
initial content is fetched from its
managed object context using the
controller's current fetch predicate.
It is important to note that the
controller's fetch is executed as a
delayed operation performed after its
managed object context is set (by nib
loading)—this therefore happens after
awakeFromNib and
windowControllerDidLoadNib:. This can
create a problem if you want to
perform an operation with the contents
of an object controller in either of
these methods, since the controller's
content is nil. You can work around
this by executing the fetch "manually"
with fetchWithRequest:merge:error:.
You pass nil as the fetch request
argument to use the default request,
as illustrated in the following code
fragment.
I added an IBOutlet to my NSArrayController within the app delegate and connected it in Interface Builder. I then added the following to the method applicationDidFinishLoading: based on the documentation in the aforementioned link:
-(void)applicationDidFinishLaunching:(NSNotification *) aNotification {
NSError *error = nil;
BOOL ok = [myArrayController fetchWithRequest:nil merge:NO error:&error];
if (ok) {
[myCustomViewController redrawMyCustomView];
}
}
Now, when I launch the application, the data populates the table and the view automatically is redrawn with the selected data.