Re: Display csv in a tableView with bindings
On Jul 26, 2009, at 5:38 PM, I. Savant wrote: On Jul 26, 2009, at 3:52 PM, Aaron Burghardt wrote: Not necessarily. If the keys are NSStrings, then they are copied when added to the dictionary, but a copy of an immutable string is optimized to just retain it, so the data isn't duplicated (assuming all rows have the same columns in the same order, an assumption you don't seem to be making). Actually, I temporarily take back my "you're probably right" response. :-) I can't find a reference to this anywhere, but I admittedly only looked in the NSString API reference, the Introduction to Strings Programming Guide for Core Foundation and quickly perused the The Objective-C 2.0 Programming Language. Would you mind directing me to where this is stated? I'm not saying you're wrong - it sounds plausible - I'm just not sure you're right. :-) I didn't think it was documented anywhere, but Adam found a reference for at least some forms. But, it's well-known on the list and easy to test (see example below). Caveat: it's an implementation detail that you normally shouldn't be concerned with. But, if you get to the point that you need to optimize memory consumption, it is worthwhile to confirm the behavior. For example, if you pass mutable strings to the method that parses the CSV, then you need to make immutable copies first. Keep in mind that an NSArrayController created in Interface Builder is defined by default to create an NSMutableDictionary for each item in the dictionary. With respect, I don't see how this is relevant to my point. It was an unnecessary point. I was interpreting your comments to be strongly advocating not using dictionaries, and I was trying to suggest it is more common than that. It's not unreasonable, and we don't know the OP's performance requirements. No, it's not unreasonable, but since we don't know the OP's performance requirements, the original blanket statement that NSDictionary is better won't do without these caveats (ie, "it's easier for bindings, but dog-slow on reasonably large files"). Rather than just say "there's more to it than that" as a drive-by correction, I wanted to provide a helpful explanation and workaround, since this is an area in which I have recent and detailed experience. :-) You brought up some good discussion points, and I probably should have asked the OP to give us more details. I inferred from his question that he didn't have a working solution, so I suggested the simplest working solution that was inline with his current mindset. I didn't mean to imply it was the best solution, but my response was so short it easily could be read that way. I assumed that if performance wasn't adequate, we would get a follow-up question. But, I think it is better to start with an easy-to-understand working solution and then optimize it if necessary. Regards, Aaron #import int main(int argc, char *argv[]) { NSAutoreleasePool *pool = [NSAutoreleasePool new]; NSString *string1, *string2; // create a string string1 = [[NSFileManager defaultManager] stringWithFileSystemRepresentation:argv[0] length:strlen(argv[0])]; NSLog(@"String value: %@", string1); NSLog(@"String 1 class: %@ address: %p retain count: %ld", NSStringFromClass([string1 class]), string1, [string1 retainCount]); string2 = [string1 copy]; NSLog(@"String 2 class: %@ address: %p retain count: %ld", NSStringFromClass([string2 class]), string2, [string2 retainCount]); // create a path-optimized string string1 = [string1 stringByDeletingLastPathComponent]; NSLog(@"String value: %@", string1); NSLog(@"String 1 class: %@ address: %p retain count: %ld", NSStringFromClass([string1 class]), string1, [string1 retainCount]); string2 = [string1 copy]; NSLog(@"String 2 class: %@ address: %p retain count: %ld", NSStringFromClass([string2 class]), string2, [string2 retainCount]); [pool drain]; return 0; } Compile on the command line with: $ gcc -framework Foundation -o test test.m An example run: $ /tmp/stringtest/test 2009-07-26 20:06:25.258 test[15385:903] String value: /tmp/stringtest/ test 2009-07-26 20:06:25.262 test[15385:903] String 1 class: NSCFString address: 0x10010c630 retain count: 1 2009-07-26 20:06:25.266 test[15385:903] String 2 class: NSCFString address: 0x10010c630 retain count: 2 2009-07-26 20:06:25.267 test[15385:903] String value: /tmp/stringtest 2009-07-26 20:06:25.267 test[15385:903] String 1 class: NSPathStore2 address: 0x100110560 retain count: 1 2009-07-26 20:06:25.268 test[15385:903] String 2 class: NSPathStore2 address: 0x100110560 retain count: 2 smime.p7s Description: S/MIME cryptographic signature ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comment
Re: Display csv in a tableView with bindings
On Jul 26, 2009, at 3:04 PM, Kyle Sluder wrote: On Jul 26, 2009, at 2:52 PM, "Adam R. Maxwell" wrote: "CFString objects perform other “tricks” to conserve memory, such as incrementing the reference count when a CFString is copied." Not every NSString is necessarily a CFString. They're toll-free bridged, but that just means the CF implementation needs to be aware of any non-NSCFString instances it is handed. I belive the private NSPathStorage class might not be a subclass of NSCFString. Correct. The same design principle applies for NS classes, though, and a quick test program shows that -[NSPathStore2 copy] returns the same pointer. IOW, just because two types are toll-free bridged does not mean they have the same behavior. Look at NSDictionary for a known example; if you create a CFDictionary with certain options and then use it as an NSDictionary you do not get the same behavior (I believe the relevant option involves whether the dictionary should copy its keys). Yeah, that's part of it. If you use pointer equality and copyWithZone: doesn't return the same object, setObject:forKey: will break your dictionary. http://www.cocoabuilder.com/archive/message/cocoa/2006/6/9/165304 smime.p7s Description: S/MIME cryptographic signature ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Display csv in a tableView with bindings
On Jul 26, 2009, at 6:09 PM, Adam R. Maxwell wrote: Can you go into a bit more detail with regard to the setting up the bindings? do I bind the tableView column to an arrayController which handles the rows? what model key path? Personally, I recommend that you avoid bindings like the plague until you're comfortable with the datasource approach. Agreed. For my case, the datasource approach was much easier to manage and didn't take away from the app at all. It's only a *little* more code than with Bindings (since KVO timing issues required some extra custom logic in several instances for me) so the decision was an easy one. -- I.S. ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Display csv in a tableView with bindings
On Jul 26, 2009, at 5:53 PM, gumbo...@mac.com wrote: Thanks People, This is excellent advice and very helpful. The main purpose of the app was to load the CSV (exported from Numbers) and turn the data into an HTML table with some hard coded CSS hooks. This works well now, but the format required from the CSV is not very flexible. Then NSDictionary will probably be fine for you. Performance test it and find out. Best test: a test file with many rows and few columns, then another with the same rows and many columns. Stick with nice round numbers and be consistent. The measure, measure, measure. Ultimately in this situation, as long as it "feels" reasonably fast, you're probably fine. This is a very nice and tidy solution, You're damn right it is! Er, what I meant was, "I humbly thank you for your compliment." ;-) I already have the tableView expanding to the size required to fit the data and the logic handles odd shaped tables. Can you go into a bit more detail with regard to the setting up the bindings? do I bind the tableView column to an arrayController which handles the rows? what model key path? Generally speaking, you'd dynamically create NSTableColumn instances as needed. For each column, you'd bind its value to the array controller's arrangedObjects.key where "key" represents the key for that column (the one that corresponds to the field in your row dictionary that the column represents). It's the same as in Interface Builder; you're just setting it up with code. See these two: http://developer.apple.com/documentation/Cocoa/Reference/CocoaBindingsRef/BindingsText/NSTableColumn.html#//apple_ref/doc/uid/NSTableColumn-DontLinkElementID_601 http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Protocols/NSKeyValueBindingCreation_Protocol/Reference/Reference.html#//apple_ref/doc/uid/20002048-BCICHGHC I imagine the largest table would be about 15x300, but I don't like making these assumptions, Murphy's law #1) I am a little concerned about this, how much sleep should I be losing over this problem? For a first-pass, none at all. Go easy first, then optimize if necessary. Your users may not even notice. Given that Numbers itself is ... how shall we say ... unconcerned with performance ( :-) ), you can probably relax a bit yourself. In my situation (I actually have two separate ones with the same requirements), performance is everything and so is the ability to heavily reorganize and otherwise curate the data prior to using it. For me, it's worth losing some sleep over. YMMV. -- I.S. ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Display csv in a tableView with bindings
On Jul 26, 2009, at 6:05 PM, Adam R. Maxwell wrote: Good point. 8--10 displayed in the table (typically), but each item has an arbitrary number of values (typically < 20, though). Users can also display an arbitrary number of columns, so there are lots of fun performance problems to find :). The value of the column-mapper architecture I outlined increases with the number of columns. :-) I'm *still* finding new ways to make it even faster. Memory usage doesn't bother me as much as taking 40 seconds to scan through the rows looking for certain values to act upon (find/replace, convert, etc.). Sorting speed is about as fast either way, though. -- I.S. ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Display csv in a tableView with bindings
On Jul 26, 2009, at 2:53 PM, gumbo...@mac.com wrote: Can you go into a bit more detail with regard to the setting up the bindings? do I bind the tableView column to an arrayController which handles the rows? what model key path? Personally, I recommend that you avoid bindings like the plague until you're comfortable with the datasource approach. Unfortunately, I know from experience that when the row count gets above 8xx,000, NSTableView can no longer accurately draw rows in the view (if they are the standard-sized text fields). But that is well beyond that magic tipping point :-) I imagine the largest table would be about 15x300, but I don't like making these assumptions, Murphy's law #1) I am a little concerned about this, how much sleep should I be losing over this problem? 15x300 is trivial. smime.p7s Description: S/MIME cryptographic signature ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Display csv in a tableView with bindings
On Jul 26, 2009, at 2:58 PM, I. Savant wrote: We have an application that keeps an array of bibliographic references, where each is an NSMutableDictionary with other properties. The largest file I recall throwing at it is ~20K items, and the main problem at that point was a beachball when using SearchKit...which was a nuisance to work around. It doesn't use bindings, but there really aren't any lazy loading tricks either. Well ... 20k items with only a couple of columns or 20k items with "many" columns. That one little detail makes all the difference. :-) Good point. 8--10 displayed in the table (typically), but each item has an arbitrary number of values (typically < 20, though). Users can also display an arbitrary number of columns, so there are lots of fun performance problems to find :). smime.p7s Description: S/MIME cryptographic signature ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Display csv in a tableView with bindings
On Jul 26, 2009, at 2:52 PM, "Adam R. Maxwell" wrote: "CFString objects perform other “tricks” to conserve memory, such as incrementing the reference count when a CFString is copied." Not every NSString is necessarily a CFString. They're toll-free bridged, but that just means the CF implementation needs to be aware of any non-NSCFString instances it is handed. I belive the private NSPathStorage class might not be a subclass of NSCFString. IOW, just because two types are toll-free bridged does not mean they have the same behavior. Look at NSDictionary for a known example; if you create a CFDictionary with certain options and then use it as an NSDictionary you do not get the same behavior (I believe the relevant option involves whether the dictionary should copy its keys). --Kyle Sluder ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Display csv in a tableView with bindings
On Jul 26, 2009, at 5:52 PM, Adam R. Maxwell wrote: "CFString objects perform other “tricks” to conserve memory, such as incrementing the reference count when a CFString is copied." http://developer.apple.com/documentation/CoreFoundation/Conceptual/CFStrings/Articles/StringStorage.html#//apple_ref/doc/uid/20001179 Exactly what I was looking for, thanks. I stand corrected and give Aaron back the "probably right" upgraded to a full "you're absolutely right". :-) "Reasonably large files" is reasonably vague :). Quite. Back to the old "we don't know the OP's requirements". Because of this, vague (and covering as many caveats as possible) is the best answer. We have an application that keeps an array of bibliographic references, where each is an NSMutableDictionary with other properties. The largest file I recall throwing at it is ~20K items, and the main problem at that point was a beachball when using SearchKit...which was a nuisance to work around. It doesn't use bindings, but there really aren't any lazy loading tricks either. Well ... 20k items with only a couple of columns or 20k items with "many" columns. That one little detail makes all the difference. :-) -- I.S. ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Display csv in a tableView with bindings
Thanks People, This is excellent advice and very helpful. The main purpose of the app was to load the CSV (exported from Numbers) and turn the data into an HTML table with some hard coded CSS hooks. This works well now, but the format required from the CSV is not very flexible. So I thought if I could display the data, somehow, the user could sort as they required and select values to add css. Well, you are correct that I assumed that it was a beginner question and that the OP was working with a fixed number of known columns (a reasonable assumption, I suppose, since he wants to use bindings). He could start with dictionaries, then switch to a custom class for rows if the performance using dictionaries was inadequate. Definitely a beginner question, I still have to squint quite hard when it comes to the magic of bindings. If you go the dictionary route, using the keys to identify the "fields" in each row, you're storing *way* more than just the individual field contents. You're storing a copy of your field identifier keys for every field, for every row. Best-case scenario, you're storing a pointer to some object that represents the "column" to which the fields belong, but this defeats the ease-of- use with bindings as you need string keys. Not necessarily. If the keys are NSStrings, then they are copied when added to the dictionary, but a copy of an immutable string is optimized to just retain it, so the data isn't duplicated (assuming all rows have the same columns in the same order, an assumption you don't seem to be making). As I mentioned above, with increasingly large files, this dramatically increases your reading/writing time and uses a lot of memory. But at least you get the ability to easily use bindings and to sort, all for free, performance be damned. Keep in mind that an NSArrayController created in Interface Builder is defined by default to create an NSMutableDictionary for each item in the dictionary. It's not unreasonable, and we don't know the OP's performance requirements. Performance just needs to be usable at this stage, once the concept is proven I can look further into this. If you go another route (an array of arrays of strings), it's far more efficient, but adds a few programming complexities: 1 - How do you sort by a column? There's no key for sort descriptors and sorting via selector provides no way to pass additional information (such as column index or identifier). 2 - To what do you bind? The same limitation that causes concern in problem #1 makes #2 difficult ... and there is little by way of over-the-counter laxative to make #2 less difficult. 3 - If you intend to allow reordering of columns (built-in NSTableView feature) or even adding/removing columns, how do you handle keeping the columns mapped to the correct fields in the row array in the absence of an associative array (dictionary)? The easiest solution to all three of these problems (in my opinion) is to make a "row" a custom class and a helper class (we'll call it "ColumnMapper" - one mapper shared among all rows). The row's internal storage can still be an array of strings for low overhead, but the Row class has a trick up its sleeve. It overrides - valueForUndefinedKey: so that it can still look up associative values (like a dictionary) but without storing them. The storage occurs once in the ColumnMapper. This is a very nice and tidy solution, I already have the tableView expanding to the size required to fit the data and the logic handles odd shaped tables. Can you go into a bit more detail with regard to the setting up the bindings? do I bind the tableView column to an arrayController which handles the rows? what model key path? Unfortunately, I know from experience that when the row count gets above 8xx,000, NSTableView can no longer accurately draw rows in the view (if they are the standard-sized text fields). But that is well beyond that magic tipping point :-) I imagine the largest table would be about 15x300, but I don't like making these assumptions, Murphy's law #1) I am a little concerned about this, how much sleep should I be losing over this problem? ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Display csv in a tableView with bindings
On Jul 26, 2009, at 2:38 PM, I. Savant wrote: On Jul 26, 2009, at 3:52 PM, Aaron Burghardt wrote: Not necessarily. If the keys are NSStrings, then they are copied when added to the dictionary, but a copy of an immutable string is optimized to just retain it, so the data isn't duplicated (assuming all rows have the same columns in the same order, an assumption you don't seem to be making). Actually, I temporarily take back my "you're probably right" response. :-) I can't find a reference to this anywhere, but I admittedly only looked in the NSString API reference, the Introduction to Strings Programming Guide for Core Foundation and quickly perused the The Objective-C 2.0 Programming Language. Would you mind directing me to where this is stated? I'm not saying you're wrong - it sounds plausible - I'm just not sure you're right. :-) "CFString objects perform other “tricks” to conserve memory, such as incrementing the reference count when a CFString is copied." http://developer.apple.com/documentation/CoreFoundation/Conceptual/CFStrings/Articles/StringStorage.html#//apple_ref/doc/uid/20001179 It's not unreasonable, and we don't know the OP's performance requirements. No, it's not unreasonable, but since we don't know the OP's performance requirements, the original blanket statement that NSDictionary is better won't do without these caveats (ie, "it's easier for bindings, but dog-slow on reasonably large files"). Rather than just say "there's more to it than that" as a drive-by correction, I wanted to provide a helpful explanation and workaround, since this is an area in which I have recent and detailed experience. :-) "Reasonably large files" is reasonably vague :). We have an application that keeps an array of bibliographic references, where each is an NSMutableDictionary with other properties. The largest file I recall throwing at it is ~20K items, and the main problem at that point was a beachball when using SearchKit...which was a nuisance to work around. It doesn't use bindings, but there really aren't any lazy loading tricks either. smime.p7s Description: S/MIME cryptographic signature ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Display csv in a tableView with bindings
On Jul 26, 2009, at 3:52 PM, Aaron Burghardt wrote: Not necessarily. If the keys are NSStrings, then they are copied when added to the dictionary, but a copy of an immutable string is optimized to just retain it, so the data isn't duplicated (assuming all rows have the same columns in the same order, an assumption you don't seem to be making). Actually, I temporarily take back my "you're probably right" response. :-) I can't find a reference to this anywhere, but I admittedly only looked in the NSString API reference, the Introduction to Strings Programming Guide for Core Foundation and quickly perused the The Objective-C 2.0 Programming Language. Would you mind directing me to where this is stated? I'm not saying you're wrong - it sounds plausible - I'm just not sure you're right. :-) Keep in mind that an NSArrayController created in Interface Builder is defined by default to create an NSMutableDictionary for each item in the dictionary. I missed this the first time around, sorry. With respect, I don't see how this is relevant to my point. It only illustrates that NSMutableDictionary is an acceptable container (and it's the default for NSArrayController because it's *the* generic Cocoa container that fits in nicely with KVC). That it's the default says nothing about its performance when there are hundreds of thousands of them to create and manipulate. It's not unreasonable, and we don't know the OP's performance requirements. No, it's not unreasonable, but since we don't know the OP's performance requirements, the original blanket statement that NSDictionary is better won't do without these caveats (ie, "it's easier for bindings, but dog-slow on reasonably large files"). Rather than just say "there's more to it than that" as a drive-by correction, I wanted to provide a helpful explanation and workaround, since this is an area in which I have recent and detailed experience. :-) -- I.S. ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Display csv in a tableView with bindings
On Sunday, July 26, 2009, Aaron Burghardt wrote: > Not necessarily. If the keys are NSStrings, then they are copied when added > to the dictionary, but a copy of an immutable string is optimized to just > retain it, so the data isn't duplicated (assuming all rows have the same > columns in the same order, an assumption you don't seem to be making). > You're probably right about the strings ... but (continued below) ... > A reasonable idea if the circumstances require it. It would certainly avoid > storing a reference to each key in each row, so it would save a little > memory, but with the mapping of indexes to column names, it may not be any > faster than a dictionary. > This I've tested. It (creation and manipulation) takes less than ten percent of the time with this method than does the dictionary approach. A dramatic difference as I said. > Unfortunately, I know from experience that when the row count gets above > 8xx,000, NSTableView can no longer accurately draw rows in the view (if they > are the standard-sized text fields). But that is well beyond that magic > tipping point :-) > It certainly does. -- I.S. ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Display csv in a tableView with bindings
On Jul 26, 2009, at 10:53 AM, I. Savant wrote: On Jul 26, 2009, at 6:32 AM, Aaron Burghardt wrote: Neither, you want an array of dictionaries where each row of CSV is a dictionary in which the values keyed to column names and each row of CSV is one dictionary object in the array. This is a bit more complicated than that, actually. There's a bit of a catch-22 here. On the one hand, you have a performance consideration. On the other, you have an ease-of- programming consideration. Using NSDictionary is easier, but for moderately-sized files it is noticeably slow, for large files, it's unusably so. Well, you are correct that I assumed that it was a beginner question and that the OP was working with a fixed number of known columns (a reasonable assumption, I suppose, since he wants to use bindings). He could start with dictionaries, then switch to a custom class for rows if the performance using dictionaries was inadequate. If you go the dictionary route, using the keys to identify the "fields" in each row, you're storing *way* more than just the individual field contents. You're storing a copy of your field identifier keys for every field, for every row. Best-case scenario, you're storing a pointer to some object that represents the "column" to which the fields belong, but this defeats the ease-of-use with bindings as you need string keys. Not necessarily. If the keys are NSStrings, then they are copied when added to the dictionary, but a copy of an immutable string is optimized to just retain it, so the data isn't duplicated (assuming all rows have the same columns in the same order, an assumption you don't seem to be making). As I mentioned above, with increasingly large files, this dramatically increases your reading/writing time and uses a lot of memory. But at least you get the ability to easily use bindings and to sort, all for free, performance be damned. Keep in mind that an NSArrayController created in Interface Builder is defined by default to create an NSMutableDictionary for each item in the dictionary. It's not unreasonable, and we don't know the OP's performance requirements. If you go another route (an array of arrays of strings), it's far more efficient, but adds a few programming complexities: 1 - How do you sort by a column? There's no key for sort descriptors and sorting via selector provides no way to pass additional information (such as column index or identifier). 2 - To what do you bind? The same limitation that causes concern in problem #1 makes #2 difficult ... and there is little by way of over- the-counter laxative to make #2 less difficult. 3 - If you intend to allow reordering of columns (built-in NSTableView feature) or even adding/removing columns, how do you handle keeping the columns mapped to the correct fields in the row array in the absence of an associative array (dictionary)? The easiest solution to all three of these problems (in my opinion) is to make a "row" a custom class and a helper class (we'll call it "ColumnMapper" - one mapper shared among all rows). The row's internal storage can still be an array of strings for low overhead, but the Row class has a trick up its sleeve. It overrides - valueForUndefinedKey: so that it can still look up associative values (like a dictionary) but without storing them. The storage occurs once in the ColumnMapper. A reasonable idea if the circumstances require it. It would certainly avoid storing a reference to each key in each row, so it would save a little memory, but with the mapping of indexes to column names, it may not be any faster than a dictionary. Of course for very large files, both methods will be slow (and memory-intensive), and the problem becomes far more complex because then you need to start considering low-level solutions that don't ignore encodings. The anthesis to this concern is that, as the complexity and size increase, the likelihood that a human will want to see it as a table they will manually manipulate decreases (or at least, the reasonableness of the request does). At that magic tipping point, it's easy to argue that a GUI editor is no longer feasible and most of this problem goes away. Unfortunately, I know from experience that when the row count gets above 8xx,000, NSTableView can no longer accurately draw rows in the view (if they are the standard-sized text fields). But that is well beyond that magic tipping point :-) Regards, Aaron smime.p7s Description: S/MIME cryptographic signature ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email s
Re: Display csv in a tableView with bindings
On Jul 26, 2009, at 12:04 PM, Scott Andrew wrote: If x number of objects in your CSV file represent an object, then parse it by hand and put the data into an object that it represents. This assumes your CSV will always represent a certain data type. That's a pretty big assumption for a data format that is purposefully wide open so that it can define a multitude of "record" formats. If you already know the structure, then it's a well-defined format and you're unlikely to be using CSV anyway. Of course, only the OP can answer this in his case. -- I.S. ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Display csv in a tableView with bindings
If x number of objects in your CSV file represent an object, then parse it by hand and put the data into an object that it represents. For example: Scott Andrew, 40, Computer Programmer These might get parsed into a contact class that has properties name, age, profession. Then the bindings can be mapped to an array of contacts. This assumes that the values represent an object. Of course there are catch 22's that are mentioned else where in this thread. Scott On Jul 24, 2009, at 5:11 PM, gumbo...@mac.com wrote: I need some direction please. I would like to load a csv file and display the contents in an NSTableView. What is the best way to achieve this with bindings? Should the model store the data in an array of arrays (rows and columns) or a dictionary of arrays (keyed columns and rows)? ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/scottandrew%40roadrunner.com This email sent to scottand...@roadrunner.com ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Display csv in a tableView with bindings
On Jul 26, 2009, at 6:32 AM, Aaron Burghardt wrote: Neither, you want an array of dictionaries where each row of CSV is a dictionary in which the values keyed to column names and each row of CSV is one dictionary object in the array. This is a bit more complicated than that, actually. There's a bit of a catch-22 here. On the one hand, you have a performance consideration. On the other, you have an ease-of- programming consideration. Using NSDictionary is easier, but for moderately-sized files it is noticeably slow, for large files, it's unusably so. If you go the dictionary route, using the keys to identify the "fields" in each row, you're storing *way* more than just the individual field contents. You're storing a copy of your field identifier keys for every field, for every row. Best-case scenario, you're storing a pointer to some object that represents the "column" to which the fields belong, but this defeats the ease-of-use with bindings as you need string keys. As I mentioned above, with increasingly large files, this dramatically increases your reading/ writing time and uses a lot of memory. But at least you get the ability to easily use bindings and to sort, all for free, performance be damned. If you go another route (an array of arrays of strings), it's far more efficient, but adds a few programming complexities: 1 - How do you sort by a column? There's no key for sort descriptors and sorting via selector provides no way to pass additional information (such as column index or identifier). 2 - To what do you bind? The same limitation that causes concern in problem #1 makes #2 difficult ... and there is little by way of over- the-counter laxative to make #2 less difficult. 3 - If you intend to allow reordering of columns (built-in NSTableView feature) or even adding/removing columns, how do you handle keeping the columns mapped to the correct fields in the row array in the absence of an associative array (dictionary)? The easiest solution to all three of these problems (in my opinion) is to make a "row" a custom class and a helper class (we'll call it "ColumnMapper" - one mapper shared among all rows). The row's internal storage can still be an array of strings for low overhead, but the Row class has a trick up its sleeve. It overrides -valueForUndefinedKey: so that it can still look up associative values (like a dictionary) but without storing them. The storage occurs once in the ColumnMapper. When asked for a field value for a column, a Row asks the ColumnMapper for the index (the index in its storage array) for the field the column represents. Likewise for storing a field value. This works because, since Row doesn't respond to these column ids as keys, it KVC falls back to -valueForUndefinedKey: and our Row class overrides this and relies on the central ColumnMapper to determine where in its internal storage the value for that column ID is located. This solves the sorting issue quite nicely too, if you sort using descriptors. Since NSSortDescriptor uses KVC, it "just works". Don't forget to google around for "Finder-like sorting" ... the built-in methods make a mess of alphanumeric strings. I leave implementing that to your imagination ... it's actually really easy if you spend a few minutes with Google. Note also this approach requires that all rows have the same number of columns/fields. Your parsing logic will have to account for this by either automatically adjusting (fraught with complexities and assumptions) or rejecting the file and informing the user of the first row where trouble begins - ie, the first row where the number of fields/columns differ from the rest. You really should take this route anyway, since the missing field in a row might be somewhere other than the end ... so what do you do with the remaining fields in the row? They are probably in the wrong column and there's no way to know because of CSV's inherent lack of solid structure. The only remaining problem is bindings. If you want to be able to handle any CSV file (ie, the "fields" are unknown), I'm afraid there's no way to use bindings in IB. You'll have to create the table columns (and bind them) in code once you've parsed your file and determined the number of columns. In this regard, you might find it just as easy (if not easier) to eschew Cocoa Bindings altogether and just use the NSTableDatasource protocol. It gives you more precise control over what to refresh and when. Trust me, this will come up. Of course for very large files, both methods will be slow (and memory-intensive), and the problem becomes far more complex because then you need to start considering low-level solutions that don't ignore encodings. The anthesis to this concern is that, as the complexity and size increase, the likelihood that a human will want to see it as a table they will
Re: Display csv in a tableView with bindings
On Jul 24, 2009, at 8:11 PM, gumbo...@mac.com wrote: I need some direction please. I would like to load a csv file and display the contents in an NSTableView. What is the best way to achieve this with bindings? Should the model store the data in an array of arrays (rows and columns) or a dictionary of arrays (keyed columns and rows)? Neither, you want an array of dictionaries where each row of CSV is a dictionary in which the values keyed to column names and each row of CSV is one dictionary object in the array. Aaron smime.p7s Description: S/MIME cryptographic signature ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Display csv in a tableView with bindings
I need some direction please. I would like to load a csv file and display the contents in an NSTableView. What is the best way to achieve this with bindings? Should the model store the data in an array of arrays (rows and columns) or a dictionary of arrays (keyed columns and rows)? ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com