Core Data KVC example - cocoa

Sorry to impose, but I would really appreciate it if someone would take a look at this and show me how to get this done:
Core Data works as expected with data associations between the Source list entry(s) and the upper right textField.
So does textField2 (lower right) if you manually type in a string.
I want to append a string in the lower textField, in this case a generic "Hello!" (implemented in the setText method) and have it also maintain it's association with the source list entry.
To summarize: textField2 - manually type in a string, it works as expected. Append the coded string, and it does not maintain it's association with the source list entry.
Here's the sample project.
Thanks again for the help.

Here's how I updated setText: method in MyDocument class:
-(IBAction)setText:(id)sender
{
NSString *newValue = [[output stringValue] stringByAppendingString:#"Hello!"];
[[setText selection] setValue:newValue forKey:#"textField2"];
}
I think your assumptions on value setting direction was wrong. Object does not take a value from the text field. It's the text field that takes value from the object. Hence I create newValue by taking current value of output text field and appending something to it. Then I take [setText selection] object (the one currently selected) and set it's textField2 property to new value. This setValue:forKey method automatically updates the output test field with new value of textField2 property.

Related

macOS command line app - User Defaults dictionaryRepresentation shows too many values

I a developing a macOS commandline application in Xcode, which uses User Defaults. I have the following code for my User Defaults
if let configDefaults = UserDefaults.init(suiteName: "com.tests.configuration") {
configDefaults.set("myStringValue", forKey: "stringKey")
configDefaults.synchronize()
print(configDefaults.dictionaryRepresentation())
}
This will create my own .plist file in the ~/Library/Preferences folder. If I look into the file, I can see only my single value which I added, which is perfectly fine. But when I call dictionaryRepresentation() on my UserDefaults object, the there are a lot of other attributes (I guess from the shared UserDefaults object), like
com.apple.trackpad.twoFingerFromRightEdgeSwipeGesture or AKLastEmailListRequestDateKey
Looking into the documentation of UserDefaults, it seems that this has to do with the search list of UserDefaults and that the standard object is in the search list:
func dictionaryRepresentation() -> [String : Any]
Returns a dictionary that contains a union of all key-value pairs in the domains in the search list.
There are also the methods addSuite and removeSuite for a UserDefaults object, so I am guessing I need to remove the .standard suite from my configDefaults object, but I don't know the name, which should be used for that in the method.
Is it possible to remove the .standard defaults from the dictionary representation? I basically just want all of my own data in a dictionary, nothing more.
The reason I am trying to get only my values from the UserDefaults, is that a have a number of object of a custom type Connection (which store the configuration to connect to a server), which are saved in the UserDefaults. On program start I want to be able to load all objects into my app. Therefore I thought I could use dictionaryRepresentation(), as it would return all elements in the UserDefaults. But then there should be only my Connection objects in the dictionary, so that I can cast it to [String: Connection].
Given your purpose (in your latest edit of your question), what you should do is store a collection of Connection objects under a single key. Then, look up that key to get the collection.
It's not clear if the collection should be an array of Connection objects or a dictionary mapping strings to Connections. That's a choice you can make.
But, in any case, you shouldn't rely on the defaults being empty of everything else.
In other words, you would do:
UserDefaults.standard.set(yourStringToConnectionDictionary, forKey:"yourSingleKey")
and later:
let connectionMap = UserDefaults.dictionary(forKey:"yourSingleKey")
then look up Connections in the connectionMap by their name/ID/whatever.
Though the other solution proposed by Ken Thomases may be better from a design standpoint, I've found a solution that does exactly what I initially wanted. Calling
UserDefaults.standard.persistentDomain(forName: "com.company.TestApp.configuration")
Returns a dictionary containing only the values I've added to the domain com.company.TestApp.configuration, using
let configs = UserDefaults.init(suiteName: "com.company.TestApp.configuration")!
configs.set(someData, forKey: someKey)
Strangely in the Apple documentation says this about persistentDomain(forName:):
Calling this method is equivalent to initializing a user defaults object with init(suiteName:) passing domainName and calling the dictionaryRepresentation() method on it.
But this is not the case (see my question). Clarification on that subject is more than welcome.

How to display selected numeric values in a comboBox

I have a numeric field in a Notes form connected to a combobox in the xpage. the values from the combobox is a list of decimal values, 1,02, 1,03 etc but they are stored as text in the keyword documents
The combobox is of type "string" (no converters) but it doesn't seem to matter if I change it to a "decimal" using converters.
comma is a decimal separator in Sweden
I fetch the keyword values using a #dbLookup
something like this.
#DbLookup(db,"vwLookupCat","BONUS","KeyWord")
When I save the document the values from the keyword document is saved as a numric value as it should. but the combobox is no longer showing the correct selected value (in edit mode) and displayes a validation error when I change it because the value is now numeric and not text as in the combobox keyword values.
or because the field was initially a text field, but when saved it is a numeric field.
<xp:comboBox id="comboBox7" value="#{doc.bonus}">
<xp:this.converter>
<xp:convertNumber type="number"></xp:convertNumber>
</xp:this.converter>
<xp:eventHandler event="onchange" submit="true" refreshMode="partial" refreshId="tbl"></xp:eventHandler>
<xp:selectItem itemLabel="Välj Bonus" itemValue="0"></xp:selectItem>
<xp:selectItems>
<xp:this.value><![CDATA[#{javascript:#DbLookup(db,"vwLookupCat","BONUS","KeyWord")}]]></xp:this.value>
</xp:selectItems>
</xp:comboBox>
Note that I am not using any validators on the combobox
I can't change the keyword field type to numeric as this is used on many other places
if doesn't help to use #Text (#Text(#DbLookup(db,"vwLookupCat","BONUS","KeyWord")))
How should I tackle this problem?
thanks in advance
Thomas
Seem to be a similar question here without solution
I can think of 2 ways you can go about it, both of which require you to make use of beans, hopefully you should already be familiar with the concept.
The conceptually righteous
The converter stays where it is. After all you want to deal with a number, you are saving a number. The converter instructs the framework to convert the returning string value from the POST into a number, and that is what you want, since also the destination field bound with the component is saved as a number.
The problem is matching such value with the list of values used to populated the options. Why? Those values are not numbers.
The solution is custom building the options rather than letting the framework doing the autoboxing from the array of string values returned from dblookup.
It pains me to write ssjs+formula but the call should be something like this:
<xp:selectItems
value="${javascript:myBeanName.getSelectItems(#DbLookup(db,"vwLookupCat","BONUS","KeyWord"))}">
</xp:selectItems>
The bean method:
public List<SelectItem> getSelectItems(String[] values) {
List<SelectItem> options = new ArrayList<SelectItem>();
for (String value : values) {
options.add(new SelectItem(Double.valueOf(value), value));
}
return options;
}
By doing this you are creating options with comparable values.
The only problem remaining is the utterly counterintuitive converter provided by IBM. Because you don't know what choosing 'number' does internally, whether it will be a Integer, a Double, a BigDecimal etc... you're stuck with more uncertainties than certainties. I have my own number converter but since I know how the IBM one works I think you can get away with the problem by specifying an additional param to the converter.
<xp:this.converter>
<xp:convertNumber type="number" integerOnly="true" />
</xp:this.converter>
I know, I know, integerOnly makes you think it will convert the value to Integer. It doesn't, it converts to Double. Lucky you! Imagine you needed an Integer!
The conceptually crappy
The other approach is to bind the combobox to a view scoped variable.
You would initialize the variable with the string converted doc value at page load and then work with that. At save time you would read the view scoped variable, convert it back to number and push the number to the doc field before saving it.

Need to find Property name

I have several tables in my application that are displaying lists of objects from classes. I have properties to represent each value in those classes as defined in the following example
...
Public Property Cod() As Int32
Get
Return _codigo
End Get
Set(ByVal Value As Int32)
_codigo = value
End Set
End Property
...
My code hides every column and then, I use the "formatarCol" method to state which columns I want shown represented as the second parameter(which must have the same name as the properties mentioned above) and the name to be displayed for that column as the third parameter.
...
Utilidades.formatarCol(.Columns, "Cod", "Cod")
Utilidades.formatarCol(.Columns, "Estab", "Estabelecimento")
Utilidades.formatarCol(.Columns, "Sel", "Sel.")
...
Everything is working fine but I was trying to rename some of the properties. If I rename said properties I have to go to each table and manually change each string. I can't just use a replace all because different classes may have properties with the same name.
I was hoping that someone had a suggestion on how to get the Property's name instead of manually adding a string so that if I need to rename a Property again I won't have to manually go through every column where it's used and change the string.
You can rename property via refactor:
Right click your property in code -> Refactor -> Rename
It will only rename property for your class and for all occurrences of that property.
To access the name of a property in a class you can use NameOf
Example:
NameOf([Namespace to class].Cod) //returns "Cod"

NSDocument detect when a new document is created as opposed to a saved document restored

I found a major problem with the architecture of my Document based app.
Basically a store the model (a simple string) in a global variable, every time the text in field changes. I have the document save this string as it's data, and restore re-opened files using this data.
Now, the major problem that I now see is that if I restore any saved file, I populate the global variable from the document in the documents "readFromData" function (works).
But if I create a new document, "readFromData" is never called, so I have no way to set the global string to "", and thus my new documents global variable is still populated with the last saved string. (I use this to put the string back into the text view on load.
So as a simple workaround, I would need to be able to use a function that is automatically called and only ever called by the creation of a new document, to set my global variable back to "".
I can not find such a function I can override. Does one exist..?
I am not sure I understand what you are trying to do.
You could use this NSDocument initializer:
/* Initialize a new empty document of a specified type,
and return it if successful.
…
You can override this method to perform initialization that
must be done when creating new documents but should not be done
when opening existing documents.
*/
- (instancetype)initWithType:(NSString *)typeName error:(NSError **)outError;
This is invoked exactly once per document at the initial creation of the document. It will not be invoked when a document is opened after being saved to disk.

NSSearchField not working as expected

I'm trying to follow Marcus Zarra in his book 'Core Data'. In the book, he makes a small sample application, but it doesn't give much help when things don't work out...
He starts out by visually designing three entities, and then adding array controllers for each entity to the main nib.
Second, he adds a tableview and some other visual components to show data from the array controllers.
So far, I have managed to follow, but now he adds a search field to the gui, and binds it to the same array controller as one of the tableviews. Expected behavior would be for the tableview to get filtered when typing in the search field, but nothing happens.
How do I find out what's wrong?
The relevant parts from the nib is as follow:
NSArrayController Recipes
- Mode = Entity
- Enitity Name = Recipe
TableView w/TableColumn
- Value Bind To Recipes
-- Controller Key = arrangedObjects
-- Model Key Path = name
Search Field
- Predicate Bind To Recipes
-- Controller Key = filterPredicate
-- Model Key Path = name
-- Display name = predicate
-- Predicate Format = keyPath contains $value
There are no relevant messages in the console.
regards,
-Vegar
The book example is wrong and will be fixed in the next printing. You can remove the Model Key Path entirely as it is never read and change the predicate format to:
name contains[c] $value

Resources