The simplest Cocoa Binding example - objective-c

I am trying to get a basic understanding of Cocoa Bindings and I would like to create a really simple project. I have a class Person which has a variable name of type NSString. Here is how I want things to work:
User enters a name into a text field and presses the "Update name" button
The string from the text field is saved to an instance of the Person class.
The label that is bound to the Person Controller (which is bound to the Person class) automatically changes its value according to the name variable of the Person instance.
I've spent hours reading various tutorials and the Apple Mac Developer Library, but each and every example only shows how to get Cocoa Bindings work with tables. When I try to develop something far more simpler I feel that I am completely lost. I have created a base project and the only thing left is to make all the bindings. I am kindly asking to make all the connections for me and hopefully provide me with an explanation. https://www.dropbox.com/sh/6hddfxyitqp6uoc/AACgaRhKBhLo6EXCVN9W6GQua?dl=0
The project is a document-based app because I will be developing an app of this type in the future.

There are several reasons why your project doesn't work so lets start again and create the simplest Cocoa Binding Example.
Create a new Xcode project, choose Cocoa Application and don't check "Use Storyboards", "Create Document-Based Application" or "Use Core Data".
Select MainMenu.xib, select the window and add a Text Field and a Label.
Add an Object Controller to the xib. Switch Prepares Content on.
Bind the Text Field to the Object Controller: bind Value to Object Controller, Controller Key selection and Model Key Path name.
Bind the Label to the Object Controller: bind Value to Object Controller, Controller Key selection and Model Key Path name.
Build, Run, Test. Enter some text and hit Return.
The controller automatically creates an instance of NSMutableDictionary which is KVO compliant for every key. When the contents of the Text Field is changed, the binding of the Text Field calls setValue:#"New Contents" forKey:#"name". This notifies the binding of the Label and the Label is updated.
Why your project doesn't work:
In the xib, the content of the Object Controller is connected to the document. The content of the controller should be a Person, not a Document. That's why you get [<Document 0x618000100750> valueForUndefinedKey:]: this class is not key value coding-compliant for the key name.. Remove this connection.
Class Person isn't KVO compliant. When the name changes, class Person doesn't emit a change notification and the binding doesn't notice the change. This can be fixed by using a property for name instead of an ivar. You don't have to use setValue:forKey: to change the name in code, person.name = [field stringValue] is ok.
The content of the Object Controller is set in the init method of the document. This is too early, the xib isn't loaded yet and the controller doesn't exist. Set the content in windowControllerDidLoadNib. Instead of addObject I would use setContent but addObject should work.

Related

Changing data between 2 view controllers objective C

I have 2 view controller: AccountViewController and ChangeEmailViewController. The account controller contains the email of the user. The user can change his email by pressing the button titled "change" and will take him to a ChangeEmailViewController. In ChangeEmailViewController, he can write the new email and click on the button titled "submit" to change the email and will show the new email in AccountViewController.(check image to see what I've done in storyboard)
image
My Questions are:
1- How I can connect both view controllers together?
2- How can I show the email of the user in the old email section in ChangeViewController?
3- How can I change the email of user in AccountViewController with the new email that the user will submit when he/she writes it in the textfield of ChangeEmailController and will be the new email in AccountViewController
Here are my answers
How I can connect both view controllers together?
You can use delegate. You can connect two viewcontrollers through delegate.
You can use NSNotificationCenter.
You can set one of them to a property of the other.
How can I show the email of the user in the old email section in ChangeViewController?
In general, you can pass the old email value when you call/create ChangeViewController. Perhaps, you will call/create instance of ChangeViewController via segue identification or Xib identification.
If you use segue identification, you can pass the value by overriding prepareForSeque.
please note: How to pass prepareForSegue: an object
If you use Xib identification, you can note below
Passing parameter from one xib to another xib
You could have another one way. If the value was stored in DB or BackEnd Server, you can get it again in ChangeViewController.
Of course, Once you think that it's better way for you.
How can I change the email of....
You can use Delegate or NSNotificationCenter.
When the value is changed, you can use call function through Delegate or send a message via NSNotificationCenter.
Well, if you have another questions, please feel free to contact me.
Thanks.

data entered in the nstableview is not saved in coredata

I am trying to build trival app in osx. I have made entity People with 3 fields: name, age and occupation. App is NOT document based.
ArrayController is binded with App Delegate in parameters section,and in the model key path, I have managedObjectContext
In the attributes inspector,as object controller I have entity name, and People as entity name.
Then I have binded the columns with the array controller, and as controller key I have arranged objects, and under model key path, I have name, age and occupation, (nstableview, has 3 columns).
On the end, I have 2 buttons, add and remove, which are connected with the array controller (add & remove respectively)
When I click on add button, empty record is created, I can edit it, and add the values. Remove button also works fine. But, when I close the app, and open it again, nothing seems to be preserved in core data.
I would like to mention at this point, that I didn't write single line of code so far, I am trying to do everything with binding.
Anyone can tell me what I missed to bind with what? I have searched stackoverflow and google, but I didn't manage to find any solution so far.
Regards, John
In case that anyone encounter the same issue...What I missed to do is connect save action with the table view...
(right click on app delegate and drag from save action to ns table view)
When i did that, problem has been solved, and my data is now saved.

One Core Data Entity Per NSPersistentDocument?

What's the best way to use Core Data if each document on disk corresponds to one Entity instance?
I have a data model file with one entity, and that entity has one attribute of name text and of type Text.
I have a Document.xib that has an NSObjectController that is set to 'Entity' mode and gets the managedObjectContext from the File's Owner. I have an NSTextField that is bound to the Object Controller for the Controller Key 'selection' and the Key Path 'text.' (This is just a test so I can figure out how Core Data works, but my eventual app will also only have one Entity instance per Document)
When I create a new document the textfield says 'No Selection' and is disabled.
I imagine that if I had a Table View or some other kind of way to select from among entity instances the selection would work but I don't nor do I want to. How can I hook up the NSObjectController to only have one Entity instance and to automatically 'select' it?
The intended behaviour is that I type something into the NSTextField, hit Save, close the document, re-open the document and the string in the textfield persists.
This is probably a really basic question but I can't find any tutorials or documents that would address this seemingly simple use case.
Ok, well I haven't figured it all out but my particular issue was being caused by the fact that nothing was being created. I switched out the NSObjectController for an NSArrayController, created an outlet for it in Document.m and added this to windowControllerDidLoadNib:
if (![self.arrayController selectedObjects]) {
[self.arrayController add:#""];
};
Now it seems to just manage the one Entity object.

Using NSArrayController without Core Data

I'm using Core Data in my OS X application where I have some TableViews bound to NSArrayControllers. The problem I'm having is when I'm trying to populate a tableview in a sheet using an array controller where I don't want the contents to persist.
Here's how the app hangs together;
Window 1 - Shows a list of users in a table view and allows adding and removing users. Contents persist via Core Data bindings.
Window 2 - Shows a list of groups in a table view. A second table view shows a list of users that belong to the selected group. Contents persist via Core Data bindings. An 'add users' button invokes a sheet for adding users to the group.
Add Users sheet - This sheet shows a table view of users that are not already members of the selected group. Pressing the close button on the sheet adds the selected users to the selected group.
Ok, so the problem I'm having is with the array controller for the Add Users sheet. When I invoke the sheet I iterate through all users and add any to the array controller if they don't already exists in the group. When I close the sheet I try to clear down the array controller using removeObject: but this causes a "can't use this method with a ModelObjectContect."
Why do I need a MOC to remove items from the array controller? It's only for display purposes so I don't need it to persist. If I set the array controllers MOC to that of my app delegate, it physically deletes the users, which I obviously don't want. I just want to remove them from the table view of the sheet.
I thought the answer might be to create another MOC to use as a scratch-pad and not tie it to a persistent store, however this just gave me a different error when using removeObject:, something along the lines of "can't remove objects that exists in another MOC."
Why am I allowed to add object to an array controller but not remove them? In cases where you don't actually want the items physically removed are you supposed to access the the underlying "content", e.g. [arraycontroller content]? I've played with this but get strange display results as it seem to be playing with the array controller's content behind it's back. If I do this, is there a way to tell the array controller "by the way, I've been tinkering with you're content and you may need to get yourself together"?
It looks to me like you shouldn't be using array controllers without Core Data, but there is numerous comments in the documentation that suggests that it works with and without core data.
Yes, you can use an array controller without a Core Data Managed Object Context. But as you're storing NSManagedObject instances inside it, I think it tries to mark them for deletion when you removed them.
If you work with managed objects and don't want the contents of the array controller to be deleted on removal, you have to bind the array controller's content to another object's property with Cocoa Bindings.
But there is a simpler solution. I suggest you to set the managed object context of the array controller to your main MOC and use a predicate to filter its content.
[arrayController setPredicate:[NSPredicate predicateWithFormat:#"NONE groups == %#", group]];
Thus, there is not need to add or remove users from the array controller as all users that are already in the group will be hidden.
You can use them with and without core data, but an array controller either uses core data (entity backed), or it doesn't. I don't think you can use one with managed objects and not have a context.
I'm not clear why you are creating objects instead of just using a fetch request?
You don't say how you are adding the "missing" users but If this is just a basic list, you could consider creating an array of proxy objects (so you aren't touching the MOC) which you can junk when the sheet is done. You could use a non-core data array controller for this, or just (gasp!) not use bindings at all and do it the old fashioned way.
Why not use [arrayController setContent:nil]

Sheet and WindowController Delegates - Is this a good approach?

I'm using a sheet to ask the user some information for an operation that the application performs. The sheet has some 10 to 15 options (split into 4 tabs, so its a relatively clean UI) that the rest of the program needs to know before proceeding.
Right now, I have a separate window controller class for the sheet called SheetController. SheetController has a delegate property and the main controller, AppController, is set as the delegate.
When the user clicks OK in the sheet the delegate is notified and a method called didClickDone:(id)sender withParameters:(id)parameters is executed. parameter is a object that contains various properties from the sheet. My question is, is this a good approach to handling Sheets and returning data from them?
Secondly, one thing that bothers me is that the parameter is just a dead object - it only has accessor methods. It doesn't do any manipulation on them as its entire purpose is to 'carry' the data to the main controller, which in turn passes the information to the Model of the program. And, unless I'm missing something, shouldn't I just declare parameter to be a normal C struct? Or is there an advantage of using an object for this sort of purpose?
EDIT: Would a passing an NSDictionary be a good compromise? I could save the returned information with their keys in the dictionary and simply pass it.
Maybe I would not notify directly the controller from the push button event handler but
call another routine that encapsualates the logic on how the data have to be commited to the model.
Don't worry about the empty object. Is a common pattern to use it and is called DataTransferObject