Tableview updates values in the twilight zone - macos

I have followed this tutorial and successfully bind my NSTableView to a core data entity.
The table is a view based cell and is populated perfectly from the core data entity.
I have + and - buttons bind to the NSArrayController. When I press the plus button a new record is added to core data and appear on the table, when I select an entry and press the minus sign, that is removed from the database. For that matter I have override this code for the add/remove keys.
#IBAction override func add(_ sender: (Any)?) {
let newApp = self.newObject() as AnyObject
newApp.setValue("New Entry", forKey: "name")
self.addObject(newApp as Any)
}
#IBAction override func remove(_ sender: (Any)?) {
// Do certain stuff before removing all selected rows
self.remove(atArrangedObjectIndexes: self.tableView!.selectedRowIndexes)
}
I made the table view cells editable. When the plus sign button is pressed a new entry is created and appear on the table with the text "New Entry". This new entry creates a core data record. Let's call it record 1.
Now I want the user to edit the entry with the name they want.
So I select the new cell and press enter. The cell is now on edit mode.
I type the new name I want to that cell, that will be passed to the core data entity.
I type, for example, BONOBO and press ENTER.
This table must contain just unique names. So, as soon as ENTER is pressed and the cell ends editing, I want to check core data to see if the name BONOBO is already taken and if it is, reject the name and tell the user to provide a new name.
This is the problem: as soon as I press ENTER, record 1 changes its name instantly from New Entry to BONOBO, before I can check if the entry already exists on the database, meaning that any check I do, will always tell me that the record exists. In fact the record exists in memory because the context was not saved yet.
I am intercepting the enter press by setting the delegate of all cells to a class and using its delegate method controlTextDidEndEditing(_ obj: Notification).
I have also tried to set an action for the textfields but the problem is the same.
How do I intercept it before the core data change happens?

The trick here is to leverage Key-Value Coding's built-in validation methods. See Object Validation.
I've never done this with a managed object, but the process seems to be the same as with regular KVC validation. You want to implement a method with the name:
validate<Key>:error:
... Where 'Key' is the name of the parameter you're trying to validate. This takes in a pointer for the value you want to validate, and another for an NSError object. Inside the method you test whether the passed-in value is acceptable. You can return true to accept it, modify the value and return true to accept a revised version, or return false to reject it outright (modifying the error object to have something to send back to the user).

Related

How to update an NSTextField programatically and have value propagate through binding

I have a case where I would like to programmatically assign the first responder to an NSTextField and then programmatically insert a value into the NSTextField as well.
I have this working with the following code:
field.window?.makeFirstResponder(field)
field.stringValue = "Auto generated value"
In the example above, field has a binding to my model. If the user chooses to edit Auto generated value and then hit the return key, the first responder is resigned and the edited value is set on my model. BUT, if the user chooses not to edit Auto generated value and hits the return key, the first responder is resigned but the model is not updated.
It's as if the field is not marked as dirty when programmatically updating the value.
I would like to avoid having to manually update the model when the case above occurs due to some complexities that I have left out in the example. I would like it to apply through whichever binding is set just like it would when the user manually types in the value.
Is this possible?
If you use binding with a NSTextField or any other AppKit control, you should perform programmatically value changes on the data source / model, instead of the other way around by manipulating the control value in code. By doing so, you will not have the problems as described in your question.
Inserting the text in the field editor starts an editing session (undocumented feature).
if window.makeFirstResponder(textField1),
let fieldEditor = textField1.currentEditor() as? NSTextView {
fieldEditor.insertText("Auto generated value", replacementRange: NSRange(location: 0, length: fieldEditor.textStorage?.length ?? 0))
}

Setting a PFObject Value with Segmented Control

Real simply -
I'm trying to create a group sharing app that allows users to create a public or private group. I have create a "CreateTableViewController" which saves an image, group name, and comments as a PFObject within Parse. This all works fine. What I want to do however, is add a Segmented Control with 2 segments (1-public, 2-private) and incorporate that into my existing PFObject method. If a user clicks "public", then the PFObject is saved with a value of public or vice versa.
As a beginner I'm sure this is an easy solve, so please share some wisdom!
A UISegmentedControl has a property to get the selected segment, you can use this on save to determine which value the user selected.
So whenever a user hits the save button in your app, get the value of that property (an int) like so for example mySegmentedControl.selectedSegmentIndex.
To automatically get notified about changes to that control, you can add a target and selector for the UIControlEventValueChanged event to your segmented control. Whenever the selected value changes, this method is called and you can call the save method of your choice on your PFObject.
[mySegmentedControl
addTarget:self
action:#selector(myMethod)
forControlEvents:UIControlEventValueChanged];
UISegmentedControl Documentation
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UISegmentedControl_Class/#//apple_ref/occ/instp/UISegmentedControl/selectedSegmentIndex

How to get the stringValue of a Text Field Cell inside a Table View after editing the cell?

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).

NSTableView - Selecting index by typing

BACKGROUND:
I have a tableview with a list of names. When you click on a name in the list, it displays additional detail information in another section of the window. Everything is connected and is working correctly.
However...
I would like to use Type Select with this table and have run into the following snag:
When I start typing a name (while the table is selected) it correctly highlights the appropriate name in the table BUT the detailed information to the right of the table does not change.
I know the reason is the code for changing the detail information is in an IBAction method which is only called when you click to select a name in the list, and uses the [sender clickedRow] call to get the index of the selected name.
I also suspect that I need to use the [tableView selectedRow] (since it is being selected, but you are not clicking on it) but I am not quite certain where or how to perform this check.
I'm also thinking that since "type select" isn't sending an action message, I won't be able to use [sender selectedRow] but rather will use [tableView selectedRow]...
QUESTION:
How can I tell when the selected row in a tableview has changed via type select?
Thanks!
Implement the tableViewSelectionDidChange: delegate method in your controller, and ensure that your controller is the NSTableView's delegate.
You could update your view with something like:
- (void)tableViewSelectionDidChange:(NSNotification *)aNotification {
[relatedView updateInformationFromRow:[[aNotification object] selectedRow]];
}
From the documentation:
tableViewSelectionDidChange: Informs the delegate that the table
view’s selection has changed.
Within that, you would update your related view. You could use the aNotification's object, which will be a NSTableViewSelectionDidChangeNotification, again from the documentation, is:
Posted after an NSTableView object's selection changes. The
notification object is the table view whose selection changed. This
notification does not contain a userInfo dictionary.

NSTableView bindings how to add a row

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).

Resources