How to do string manipulation in an NSValueTransformer? - objective-c

I have a table column that I'm binding to a value in an NSArrayController. What I'm trying to do is display only a substring of the actual value in the array controller. The way I've been trying to do that so far is by creating an NSValueTransformer subclass, and then doing the string manipulation in the transformedValue method. However, I can't figure out how to get the incoming value turned into a string (it's of type NSConcreteValue), and maybe there's an easier way to do this without value transformers.

Sounds like you're doing presentation-side formatting, in which case you should be using a formatter instead.
Then again, if this is a string containing multiple values (e.g., something like “from 42 to 100”), you should make a model object from it instead, and store those in the array controller. Then you can bind your table columns to specific properties of the model objects, and not have to worry about picking the string apart and then reassembling it (except when you load and later save the model).
Edit: Never mind; I didn't see that the object values are NSValues, not NSStrings.

You can get a string representation of any object using the -description method, but for instances of NSValue it's unlikely to print anything especially meaningful. In other words, it's up to your value transformer to interpret the passed-in object and produce a string. If it's an NSValue instance, the question is what type of data that instance contains. Once you know that, you can write code to represent it as a string (similar to NSStringFromRect()).

Related

Writing objects to plain text in NSUserDefaults

How can I write an object to NSUserDefaults as plain text?
I've written a unit conversion system for a scientific application that basically operates around the principal of "unit objects". These objects represent a specific unit with a specific value in a given domain. The domain is represented by the class name, since everything is organized so that a time unit is literally called "TimeUnit" and a length unit is literally called "LengthUnit".
The current value of a "unit" is represented by a double, and the "unit" itself (ie, "meters", "kelvin", "hours", "pounds", etc) is represented by an NSString.
I need to be able to write these objects to NSUserDefaults.
I've already implemented a system using NSCoding and NSKeyedArchiver. This works great, I can store and retrieve units from NSUserDefaults and everything works.
The problem is that the output from NSKeyedArchiver is too big. The base64 encoded data you get from it is this gigantic chunk of characters, which is impossible to change through a plain text editor and somewhat difficult to debug. I know you can override this to a certain extent by using NSPropertyListXMLFormat_v1_0 with NSKeyedArchiver's setOutputFormat, but even that produces a fairly verbose output with a whole bunch of stuff I don't really care about (I know all that data is there for a reason, but I'm guessing that's because NSKeyedArchiver is designed to handle a lot of different situations).
It would be much easier if I could encode these objects using my own format. Something almost like:
class_name:double_value:unit_name
So a temperature unit with a value of 22 degrees celsius would become:
TemperatureUnit:22:celsius
What is the best way of achieving something like this? Should I be subclassing NSCoder? Will this let me store the objects as a plain text string in NSUserDefaults and not a base64 encoded chunk of binary data?
For something like this you could add "serialize" and "deserialize" methods (or whatever names you want). The former returns a string and the latter takes a string and returns your object.
+ (MyUnitClass *)deserialize:(NSString *)encodedString {
// split string, create new object, assign values
}
- (NSString *)serialize {
return [NSString stringWithFormat:#"%#:%f:%#", self.classname, self.double_value, self.unit_name];
}
Now you can call serialize on one of your objects and store the string in NSUserDefaults. Use deserialize to create an object from a string you have stored in NSUserDefaults.

How can I read data from the general pasteboard for all classes?

At the moment I'm using readObjectsForClasses: to retrieve a list of objects from the general pasteboard in cocoa, which works whenever I want to only retrieve objects of a certain class e.g. NSString or NSImage etc.
However, I would like to be able to read every single object in it without having to make an array of all of their classes, such that the array returned would contain every single item in the pasteboard.
Is this possible?
Have you tried using the types method of the NSPasteboard object? I haven't tried it but the documentation says:
Return Value
An array of NSString objects containing the union of
the types of data declared for all the pasteboard items on the
receiver. The returned types are listed in the order they were
declared.
With this method you can probably query the pasteboard types, even if you won't be able to read them.

What is the preferred datatype to parse JSON into in Objective-C?

What is the preferred datatype to parse JSON into in Objective-C? I'm looking for a data type that mirrors the ability to use key=>value style and just array form.
Typically libraries (such as SBJson) will return their parsed results as either an NSArray or an NSDictionary, just depending on if the parsed JSON element was an object or an array.
From SBJsonParser.h:
/**
#brief Return the object represented by the given string
This method converts its input to an NSData object containing UTF8 and calls -objectWithData: with it.
#return The NSArray or NSDictionary represented by the object, or nil if an error occured.
*/
- (id)objectWithString:(NSString *)repr;
In your question you asked "I'm looking for a data type that mirrors the ability to use key=>value", that is by definition exactly what a dictionary is... so, you're probably looking for NSDictionary.
The question doesn't make any sense. The JSON string itself determines what type of object you are going to get when it's deserialized. It can be a string, number, array or dictionary. You have to be prepared to receive any of those. If you use NSJSONSerialization, you'll notice that the decoding methods return id, which means you don't know the type ahead of time. You will have to use isKindOfClass: to figure out what you actually got back.

How to show calculated values in NSTableView?

I have an NSTableView that binds via an NSArrayController to an NSMutableArray of NSString's.
There's also a TextView in the same window. What I want to do is display a number of occurrences of each NSString in the NSTableView.
I've thought of a way to do this, but that doesn't look elegant way of doing this:
Inherit from NSString and define new method that performs a search in predefined object (NSTextView) and returns the number of occurrences.
I'm guessing there must be a more natural way of achieving the same result?
EDIT:
Sorry, should have clarified. NSSMutableArray is an array of NSObjects that have an NSString property. I suppose I could define an extra method (findAllOccurencesOfString:inString:) which would return a number. But the question is how do I bind to this function and in that binding how to I pass a var (pointer to textField)??
You'll need to have a wordCount (read only) property on whatever objects are in your table data source, this will have to call your new method internally using the object's own string value, as you can't pass parameters in bindings (unless they've changed, I haven't used bindings for a while as I've been concentrating on iOS). Then bind to this property for the column in the table. Presumably you don't need to pass the pointer to the textfield as there is only one?

How to get NSFormatter subclass to work with NSTableColumn sort key and selector?

My setup:
I have a sqlite database from which I populate a NSMutableArray of NSDictionary objects this is the DataSource for my NSTableView.
One of the columns holds "time", the time is a float that holds seconds.
I would like to display the values in this column as minutes:seconds. For instance my data would be 123.4329387 I want to display 2:03 which I have no problem doing with a subclass of NSFormatter (or NSNumberFormatter) applied to my NSTextField in the column.
I have sorting set up by using the Table Column Attributes in IB, I just have the sort key set to "time" and the selector set to "compare:" which works fine without the formatter.
Currently this gives me something like this when I sort (descending)
1:37, 1:31, 0:10, 0:10, 0:09, 1:30, 1:30, 1:26, 0:09
and similar nonsense, it looks like something is going on but it's definitely not sorted.
How do I get the sort to look at the underlying data instead of the formatted value? Alternately, how do I specify a custom sort method and where do I put the code for said method? I have searched around quite a bit and have not found anything to help me out with this problem, any help with this is most appreciated.
It turns out that when it was sorting it was using compare: from the NSString class but it was using the underlying numeric data. I'm not exactly sure what all is going on under the hood here but I managed to fix this by creating my own compare method in a category of NSString called "timeCompare". Then in interface builder I just put "timeCompare:" in the selector field for the the table column. This gets it to call my custom compare method from which I just converted the strings given to NSNumbers and call compare: on them.