Re: Problem with garbage collection in server application [solved]
Hi Quincey, The way you broke this down was very helpful, and it turned out to be a combination of two things you alluded to. I'd been on the right track that it had to do with NIB objects, and thinking about it as you laid out helped identify the problem. On 2011-01-23, at 12:28 AM, Quincey Morris wrote: > 1. Too much "live" (i.e. uncollectible) data at once. This breaks down into > three subcategories: > > 1a. Objects that you create, and keep strong references to, use too much > memory in total. > > 1b. Your code depends on a confusion between the end of the lifetimes of your > objects and the collection times of the memory they use. You shouldn't be > designing with collection times in mind. > > 1c. Objects that are created by the frameworks internally, but which somehow > support objects that you create (think of a cache, for example), have > lifetimes not under your control, and remain live after your own objects' > lifetimes are over. I think it's mostly 1c. So in the end the problem was that I had some NIB files with NSArrayControllers bound to my 'datasets' array. The large dataset objects are removed from the array when I am done with them, and since this constitutes the last strong reference I'd (deliberately) created I expected them to be eligible for collection. However I initially assumed that removing the objects from the array would also remove any references in bound NIB objects right away. This turned out to be the source of what to me was unexpected behaviour. Although the UI objects seem to be removed from the view on cue, it's up to the collector when they will actually be reaped. As soon as my server app exits the method invoked by the client via an NSConnection, there is typically another message waiting that gets executed right away. This seems to block collection of the UI objects, which must have strong references to my dataset objects. The UI objects only get collected after the last message is sent from the client, and the server resumes the 'waiting for user input' state. In my app the UI content that is bound to attributes of the datasets is largely for logging purposes, and I can just as easily bind to an array of lightweight proxy objects that have all of the relevant information. As soon as I removed the single binding of an NSArrayController to my 'datasets' array, the objects were collected pretty much right away (right after collectExhaustively). Now I know I shouldn't be thinking about collection times, but now I think I understand the problem better. By creating strong references between NIB objects and my internal objects, I no longer had control of the last strong reference to the object. The rapidly successive client connections to the server in script mode were blocking collection of the UI objects, guaranteeing that all of the large dataset objects would be kept alive as long as the script was running. After removing direct NIB bindings to the dataset objects, the memory usage behaves exactly as expected. This all jives with a clue I'd noticed all along - the server app basically manipulates two types of object: datasets, and processing operations. From the start I had been binding the UI to lightweight proxies of the processing operations. I'd noticed that the processing operations had always been collected very promptly after the last reference was removed. Now it makes perfect sense! Oh garbage collector, I am sorry that I ever doubted you... Rick ___ 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: Problem with garbage collection in server application
On 2011-01-23, at 12:59 AM, Dave Keck wrote: > On the other > hand, if I understood you correctly in that you're seeing a 10% > speedup when using GC, then perhaps that would warrant the extra > effort. On the other-other-hand, it sounds like you might be > optimizing early. Sorry the comment about the 10% speedup (4m30s instead of 5m00s) was just an aside - based on some of the anti-GC comments I've heard I wouldn't have expected this. In fact both approaches are quite fast considering what is done - the slowdown happens when the cumulative memory consumption starts getting very high. ___ 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: Problem with garbage collection in server application
Sorry - I forgot to mention that I am indeed wrapping my code in its own autorelease pool. This should ensure that the only retain count remaining is from intentional retains by other objects that need to reference my datasets. Rick On 2011-01-23, at 12:59 AM, Dave Keck wrote: > The autorelease pool is popped after the current iteration of the run > loop exits. If the datasets are autoreleased explicitly by you, or > implicitly by any number of APIs that you call, then indeed the > objects won't be deallocated until the run loop iteration exits. If > you need (more) determinate behavior over your datasets' deallocation, > surrounding your loop with its own autorelease pool is probably the > solution. It doesn't sound like that solution would translate to your > production code, though. ___ 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: Problem with garbage collection in server application
Hi Quincy, Thanks so much for the detailed reply. On 2011-01-23, at 12:28 AM, Quincey Morris wrote: >> [...] > > You *cannot* rely on GC to satisfy your timing requirements for releasing > resources used by your application. You can't even rely rely on GC to release > memory at all, in any deterministic sense -- its function (conceptually) is > to make memory available when it's asked for, and *not* simply to release > unused memory. It's certainly true that *this* garbage collector always > releases unused memory, eventually, but the timing is unpredictable. I am indeed learning this the hard way - it does work very well for some of the apps we use, but the present project might be an edge case. > If your application is crashing due to running out of memory, looking at what > happens at 'finalize' time is probably not going to get you anywhere useful. > I think you have to start by diagnosing the problem more exactly, into one of > these categories: > > 1. Too much "live" (i.e. uncollectible) data at once. This breaks down into > three subcategories: > > 1a. Objects that you create, and keep strong references to, use too much > memory in total. It's clear that, ultimately, too much memory is retained. However I'm pretty sure that all the strong references I create are cleared at the appropriate times. However the scenarios you raise below are very relevant. > 1b. Your code depends on a confusion between the end of the lifetimes of your > objects and the collection times of the memory they use. You shouldn't be > designing with collection times in mind. Guilty as charged. However I would like to think that some of the really useless memory, possibly referenced only by internal pointers I don't control, should be cleared before the system grinds to a near halt and the app ultimately crashes. I am suspecting problem 1c might be the reason. > 1c. Objects that are created by the frameworks internally, but which somehow > support objects that you create (think of a cache, for example), have > lifetimes not under your control, and remain live after your own objects' > lifetimes are over. It's clear when breaking on retain in the non-GC version that there are a lot of KVO copies of my objects and other UI things that must be creating strong references to the large dataset objects. All of these UI objects vanish from the window at the appropriate time, but it's quite likely that they don't actually get collected until much later. It's very possible that these UI objects, with their strong references to my dataset object, are keeping the dataset objects alive. A solution might be to bind the UI elements to a lightweight proxy of my object to avoid any strong references between the UI and the big datasets. This might only be making more complexity for nothing though... > (That's the scenario where I ran into a problem similar to yours -- Core Data > has an internal cache that can't be controlled outside of the frameworks, and > it can get very large in very strange ways. I spent months of my life trying > to solve the resultant memory issues.) I can't think of anything beyond the UI objects that would be doing this. I'm not using Core Data but will have to keep this type of thing in mind. > 2. You outrun the collector. Certain patterns of data usage can interact > badly with the GC heuristics. Submitting a bug report is a good idea, because > Apple likes to find the edge cases. That likely won't help with finding an > immediate solution, of course. I'll have to put together a toy program to model this. Basically I create big (200MB) objects every few seconds, and do a few operations on them, save the results, and 'close' them. The 'close' should clear all strong references that I control. > 3. There's bug in the collector. Not likely, but possible. Agree the problem's probably in my code. > If you've designed your application carefully, then problem 1a likely means > you have a bug somewhere in your code. Problem 1b is an application design > flaw. All the other problems (1c-3) basically suck, because you're dealing > with behavior outside your control. > > Switching to a retain/release pattern is unlikely to help. It has the > essentially the same limitations as GC with regard to resource releasing, > though you can get away with Doing It Wrong more often. I think the retain/release has potential, but it did provide a strong clue that UI objects hanging around until the end of the runloop might be to blame. I forgot to mention that I wrap the code creating the objects in my own autorelease pool, to keep the objects alive long enough for me to retain them where they will actually be needed. > I don't want to sound too discouraging here. My suggestion is to put the > collection timing (and finalize) out of your mind, and concentrate on the > crashes instead. At that moment, you want to know not what's pending > collection, but wha
Re: Problem with garbage collection in server application
On 2011-01-23, at 12:04 AM, Dave Keck wrote: ... >> > I would use gdb's "info gc-roots 0x" command to determine what > strong references exist to the objects that are placed in your array. > Instruments may also have some related functionality. Thanks - I was focusing on Instruments, and I could not find a way to find the root objects. Will try gc-roots as it sounds like this will go to the heart of the 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: Problem with garbage collection in server application
Thanks Scott, On 2011-01-22, at 11:58 PM, Scott Ribe wrote: > You might try something like usleep(1000) just to see what happens. You might > not need any real delay; you might just need to yield... Tried the above, but the GC version goes back to ballooning memory usage and eventual crash. It seems the time delay really has an impact. Rick ___ 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: Problem with garbage collection in server application
On 2011-01-20, at 10:54 AM, Rick Hoge wrote: [...] > I have overridden the 'finalize' method of the dataset class to print a log > message before calling [super finalize], and when I perform a single > processing 'run' in which the client sends a message to the server directing > it to load a 200MB dataset and then perform a series of processing operations > which result in five datasets being open, I have noticed that - while the > finalize methods are indeed called - they are called around five to ten > seconds after the last processing directive is sent from the client. > For five datasets the above behaviour is not a problem, but in more realistic > tests where we generate five datasets, flush, then generate five more, before > repeating the cycle perhaps 10 times, the finalize methods never appear to be > called (or at least no log messages appear). The memory usage becomes huge, > and eventually the program crashes. I worked up a version of our app that uses retain/release style memory management, and was surprised to note that a similar thing was happening (although the memory use did not get as big). Running a script that would send five sequential processing requests to the server, with a 'close all' at the end, would result in immediate deallocation of all five datasets. However if I put the script commands inside a for loop (scripted to repeat two or more times), then the datasets are not deallocated until the end of all loops. I put a breakpoint on 'retain' in my dataset objects, and it's clear that they are getting a lot of retains from various observer objects in the user interface used to monitor script execution. The UI objects must be getting dealloc'ed themselves, as the dataset objects are eventually released. I noticed that if I put a 'sleep 1' at the bottom of the loop in my shell script, then the dataset objects would indeed be deallocated at the bottom of the loop (not after all loops). So it might be that all the KVO stuff for the UI is getting cleaned up very late in the run loop, in a process that is interrupted by another message to the NSConnection immediately upon exit. After seeing this in the retain/release version, I then tried running the GC version with the 'sleep 1' at the bottom of the loop. Lo and behold, the objects were getting finalized at the bottom of each loop (slightly asynchronously from the main thread, but that's fine). A number of tests also showed that the GC version ran around 10% faster for long processing runs. So maybe all this is a symptom of an uncontrolled interaction between the NSConnection I use to run client requests, and the NSRunLoop that is associated with the UI. Perhaps I should be looking for some way to force the app to wait until the end of the current runloop before accepting another message on the NSConnection, but I'm not sure how to do that. Of course I could also just put a sleep(1); in the code after removing references to the dataset objects and calling collectExhaustively, but this seems pretty crude and who knows if 1 second will be long enough for some ultra-large processing run (although it works just as well as a shell sleep in my test runs). I was very close to giving up on GC, but maybe this is a vital clue. It was certainly not fun to add all the dealloc methods for my limited testing... Thanks again for any help, Rick ___ 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
Problem with garbage collection in server application
I have an application based on the "Cocoa Application" template in Xcode (x86_64, currently testing on OSX 10.6.5) that listens for client messages using an NSConnection. Both client and server have been designed for garbage collection, and are compiled GC-only. The client is a simple command-line program that uses [NSConnection rootProxyForConnectionWithRegisteredName:serverName host:nil]; to send it's messages to the server. The messages direct the server to load large-ish data files (200MB) and perform processing on them. Periodically the client may direct the server to unload all of the large datasets from memory, which the server does by calling the 'removeAllObjects' method of a mutable array that holds the list of all loaded datasets. Under real conditions, we would expect to load around five of these datasets at a time, perform processing, unload, and then load another five. I have overridden the 'finalize' method of the dataset class to print a log message before calling [super finalize], and when I perform a single processing 'run' in which the client sends a message to the server directing it to load a 200MB dataset and then perform a series of processing operations which result in five datasets being open, I have noticed that - while the finalize methods are indeed called - they are called around five to ten seconds after the last processing directive is sent from the client. For five datasets the above behaviour is not a problem, but in more realistic tests where we generate five datasets, flush, then generate five more, before repeating the cycle perhaps 10 times, the finalize methods never appear to be called (or at least no log messages appear). The memory usage becomes huge, and eventually the program crashes. In these runs, a shell script repeatedly invokes the client program to send messages to the server program. The server (which has a UI) might spend all it's time in an 'inactive' state with no user input. The commands are currently run on the main thread of the server. However the memory accumulation and crash happen whether or not I click on the server window to bring it to the foreground. I'm pretty sure I'm not leaking the memory with an unintended reference, as the datasets *are* collected (albeit not very quickly) after I run a set of five operations and the server returns to be waiting for user input. I'm wondering if it could be because collection will not happen until the end of a run loop, and by bombarding the server with messages then collection is never triggered because it never senses the end of the run loop. I gather that there may be special considerations with runloops and NSConnection. Note that I *am* calling collectExhaustively right after the various stages in the server when data should be flushed, but this does not seem to help. I do the call at the end of the method in which client messages are processed - is it possible this should be run using performSelector after the current run loop? I'm at the point where I am reconsidering whether GC is really appropriate for this application, but also think I may well be doing something silly that can easily be fixed. Would be grateful for any suggestions! Rick ___ 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: Bound array item is repeatedly copied and collected while scrolling table view
... I noticed that, while I scrolled in the tableview, many copies of these large objects were being created and then immediately collected. ... NSCells used to display table content copies the object it display. Instead of binding the cell value to your object directly, bind it to its description or an other relevant property. Thanks for this suggestion, which clarifies things a bit. I thought about binding to 'description', but I want to be able to edit items in the table view when appropriate (it is not for my dataset object). I use the 'editable' binding to prevent edits to complex objects which shouldn't be edited in a collection view. Cheers, Rick ___ 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: Bound array item is repeatedly copied and collected while scrolling table view
... The array items are NSDictionaries, and one of these dictionaries contains a large dataset object that consumes a lot of memory. I noticed that, while I scrolled in the tableview, many copies of these large objects were being created and then immediately collected. It's not the table view's fault. What generates the description for the data set? You wrote a 'description' method? How long is the string it returns? If the property to which a table column is bound has the "copy" attribute, then the value will indeed be copied every time the table view fetches a value for the column. Does you "large dataset object" support NSCopying? However, since you've chosen to use dictionary instead of real properties, this seems unlikely to be the cause of your problem, unless there's more you haven't told us. My bet's on a giant description string the size of Manhattan. No - I don't override 'description' for my dataset class. The string presumably generated by NSObject's description method is displayed. My NLVolumeDataset does indeed support both NSCopying and NSMutableCopying. I know that this class's copyWithZone: method is called, and then very shortly thereafter 'finalize' is called. So it (the NSArrayController?) just seems to be firing off these huge copies so that it can call 'description' on them to display in the table, then discarding them. I agree it's not the table view's fault - it's just that even scrolling the table slightly so that the NLVolumeDataset entry comes in and out of view leads to the generation of large numbers of new copies. Thanks for the comments, Rick ___ 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/rickhoge1%40mac.com This email sent to rickho...@mac.com (43092.6825) ___ 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
Bound array item is repeatedly copied and collected while scrolling table view
I have a nib file in which entries in an NSTableView are bound to an NSMutableArray via an NSArrayController. It is used in an application running under garbage collection. The array items are NSDictionaries, and one of these dictionaries contains a large dataset object that consumes a lot of memory. I noticed that, while I scrolled in the tableview, many copies of these large objects were being created and then immediately collected. This might have something to do with the way that proxy objects are used by the array controller, or perhaps it is because the 'dataset' object is itself an entry in one of the table columns (presenting the string generated by the default 'description' method). Either way, this is detrimental to performance and memory footprint since these objects are huge (and I wouldn't normally have expected or wanted them to be copied). Is there any way to control this behavior, for example forcing the actual object to be used instead of these transient copies? Failing that, I am wondering (yes, I know this is ugly) if there is a way to set up some kind of context flag so that my object's 'copy' methods will just return a lightweight proxy when being called in this kind of situation (copied as part of a dictionary that is itself being copied)? The 'dataset' object implements both mutable and immutable copying. It is the 'immutable' copy method that is called during table scrolling. Thanks for any insight someone can offer, Rick ___ 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: NSArrayController's add: swaps entire content array when array is accessed via keypath
Quincey, Keary, thanks for the replies - ... All worked fine, except that, when the new dictionaries are added by clicking the add: button, the mutable array managed by the controller is replaced with a new array (rather than inserting the new dictionary in the original array). The new array has the correct content, apparently having copied all the pre-existing dictionaries from the old array. This is correct. NSMutableDictionary implements 'setValue:forKey:' (as a convenience, to provide very basic KVC compliance) but it doesn't implement any indexed accessors, so the array is updated via this 'setValue:forKey:', which means that the array is completely replaced. If you look at: http://developer.apple.com/documentation/Cocoa/Conceptual/KeyValueCoding/Concepts/SearchImplementation.html#/ /apple_ref/doc/uid/2955-SW2 you'll see that case (1) doesn't apply, but case (2) does. I confirmed that if subArray is promoted to an instance variable, then add: will perform an insertion rather than creating a new array (in fact I've used this a lot in the past). It seems that having the array be part of a mutable compound object results in creation of a new, copied array instead of an insertion. Presumably you haven't overridden 'accessInstanceVariablesDirectly:' to return NO in your "certain object", so now case (3) applies, and that results in the array being updated instead of replaced. The problem you've got is that you want "subArray" to behave like a fully KVO compliant indexed property, but you haven't implemented it as such. I guess I was lulled into thinking it wouldn't require any coding, since the array controller always did insertions when it was bound to an instance variable. Now it makes sense that the dictionary behaves differently from the object. Thanks again, Rick 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/rickhoge1%40mac.com This email sent to rickho...@mac.com (43092.6825) ___ 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
NSArrayController's add: swaps entire content array when array is accessed via keypath
I recently tried a design where a certain object had an NSMutableDictionary instance variable, which in turn contained an NSMutableArray entry. After initializing this setup (in -init) as shown here: topLevelDictionary = [NSMutableDictionary dictionary]; // An instance variable - I'm using GC [topLevelDictionary setValue:[NSMutableArray array] forKey:@"subArray"]; I then proceeded to add an NSTableView and NSArrayController to the nib file, binding the controller's content array to the keypath "topLevelDictionary.subArray" I then set the controller's mode to 'Class' and set the flag to prepare content, which was an NSMutableDictionary. Next I added a button which was connected to the array controller's add: method, and launched the app. All worked fine, except that, when the new dictionaries are added by clicking the add: button, the mutable array managed by the controller is replaced with a new array (rather than inserting the new dictionary in the original array). The new array has the correct content, apparently having copied all the pre-existing dictionaries from the old array. This would be ok, except that I observe changes to topLevelDictionary.subArray (see below) and need to perform special processing on new items inserted in the subArray. This only works if -observeValueForKeyPath:ofObject:change:context: is called with a change type of NSKeyValueChangeInsertion, and I can access the inserted items using [change valueForKey:NSKeyValueChangeNewKey] I confirmed that if subArray is promoted to an instance variable, then add: will perform an insertion rather than creating a new array (in fact I've used this a lot in the past). It seems that having the array be part of a mutable compound object results in creation of a new, copied array instead of an insertion. There are a number of ways I can work around this, but I don't really understand why this difference in behavior (array accessed as instance variable vs. keypath inside compound object) is happening. Is this a bug? or does it make sense in some way? This all would have been really simple if it worked as expected... Thanks for any insight anyone can provide, Rick ___ 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: Triggering change notifications when modifying custom object ivars in core data app
Just a follow-up. It's not perfect, and I'll revisit the design, but it does what I need for now. Specifically my entity has a 'transformable' attribute for which the values are a custom object class, and this object class has an ivar that is an NSMutableDictionary. The user can modify entries in this dictionary, and I would like this to cause the context to be flagged as dirty and to have the custom object flagged to be updated in the persistent store. I got this all to work the way I need using the following strategy: 1) I used the dual representation (transient object + persistent transformable data) for my custom object attribute, as described in the Core Data docs on Non-Standard Persistent Attributes. 2) When the entity is fetched I create the transient object representation from the persistent data attribute. When the entity is fetched or inserted I add an observer for every entry in the dictionary of the custom object. 3) If one of the observers is triggered, I invoke will/ didChangeValueForKey: for the persistent data attribute. This causes the context to be flagged as dirty if a dictionary entry is changed. 4) I implement -willSave in the entity's class, and here assign the persistent data attribute as shown in the Core Data doc example for the "Delayed-Update Set Accessor". This assignment causes the data to be rewritten to the disk store. The objects themselves are pretty light-weight, so the fact that they will be re-written on every save is not a huge deal. This is a relatively small part of the whole app, so I can live for now with the fact that changes to these dictionary entries won't benefit from undo/redo. In fact the objects in question are shared with a number of other apps that don't have undo/redo, so this will not be too shocking to the users (although it would have been nice). ___ 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: Triggering change notifications when modifying custom object ivars in core data app
Ben, Quincey, Sean, thanks for the comments. Maybe there are some lower level design issues to rethink. This pattern is usually a flawed model design. If the properties are to be this independently mutable, then there should be a relationship, and/or the complex attribute should be decomposed into several attributes. This is, after all, a gross violation of encapsulation. Issuing calls to will/didChange manually won't help since the property didn't change. will/didChange calls need to bracket the actual change. In theory, you could add a transient "generation count", and have every client who hacks on the mutable dictionary out from underneath your managed object increment it. Hard to see what that buys you over, say, writing proper setters and getters for the sub-properties stored in the dictionary, and stop clients mutating the dictionary directly. Restore clean encapsulation. The core data app I'm working on manages a database of images, and is also supposed to allow construction of a sequence of image processing operations. A processing operation is implemented as an instance of an 'operation' class (loaded as plugins which must be shared with non- core-data apps), which has a dictionary of input parameters and output values (similar to an Image Unit). In general, the core data app does not know what kind of input parameters will be supported by the 'operation' objects it has to represent, although these are always contained in a mutable dictionary. This means that the core data app can't really provide getters and setters because the actual parameter names (dictionary keys) are not known until run time. In the core data app, I am creating an entity to represent an operation, with the actual operation object as a custom attribute (as per the docs). The user can change the input parameters in the object's dictionary of inputs, and this should be reflected in the persistent store of corresponding to the custom attribute on disk. I realize this is ugly, but I can't think of any other way to do it given that the available operation classes are loaded as plugins at run time. It is almost working, but I need a way to tell the persistent store coordinator to re-archive the custom attribute even though only the contents and not the actual object have changed. One thing I could do, I suppose, is to add a set of parameter entities as a to-many relationship of the operation entity. This could be populated when the operation object is 'loaded' (added to the sequence), and the user would edit the parameter entities. Just before the operation object is to be run, I could update its 'inputs' dictionary based on the core data entities. This creates other difficulties however (for example the operation objects can manage a user interface view used to visualize the configuration settings). It would be nice if undo/redo worked, although for this small component of the application it would not be the end of the world if it didn't. Again, if anyone has ideas on how to approach this design I'd be very grateful. Rick ___ 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: Triggering change notifications when modifying custom object ivars in core data app
On 28-May-09, at 12:56 PM, Dave Fernandes wrote: When the instance variable changes in your custom class, you can call willChangeValueForKey: and didChangeValueForKey: for the entity that contains your custom class. I haven't ever had to do this, but it is the first thing I would try. Thanks - you know it's funny I was just trying something like this, and it seems to work - partly. In the custom entity class I enumerated all the keys in the dictionary ivar (on fetch and insert), adding appropriate observers for each one. This can be used to fire observeValueForKeyPath: in the entity's class, where I tried calling will/didChangeValueForKey: for the persistent representation of the custom class. This caused an infinite loop where these change notifications kept triggering the observer, but I think I'm close. Maybe I can use the change dictionary in observeValueForKeyPath: to break out of the loop when there's no real change. Rick On May 28, 2009, at 12:34 PM, Rick Hoge wrote: On 28-May-09, at 10:39 AM, Keary Suska wrote: On May 28, 2009, at 7:03 AM, Rick Hoge wrote: I have a core data (doc-based) app in which one of the entities includes a custom object as a persistent attribute. The custom object class implements NSCoding, and these objects are saved to the core data store with no problem (they are read back correctly etc). Instance variables of the custom object are exposed in the user interface, and can be edited by the user. The problem I have is that changes to instance variables of these custom objects are not reported to the managed object context, so the core data document is not flagged as dirty and, even if I force a save by adding an entity and invoking save, the modified custom object is not saved (if I quit and reload the old ivar values are loaded). http://developer.apple.com/documentation/Cocoa/Conceptual/CoreData/Articles/cdNSAttributes.html#/ /apple_ref/doc/uid/TP40001919 Thanks - I'd looked at this, and following the information there is what allowed me to insert and display custom object attributes. The documentation shows examples in which an attribute of type NSColor can be set and archived. My problem is that I'm dealing with a complex object type (I have what I think are good reasons for doing this) and I need to flag the context as dirty if an ivar of the custom object is modified. Specifically my entity has a 'transformable' attribute for which the values are a custom object class, and this object class has an ivar that is an NSMutableDictionary. The user can modify entries in this dictionary, and I would like this to cause the context to be flagged as dirty and to have the custom object flagged to be updated in the persistent store. Hope this clarifies things, and thanks again for the suggestion. Rick Keary Suska Esoteritech, Inc. "Demystifying technology for your home or business" (43092.6825) ___ 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/dave.fernandes%40utoronto.ca This email sent to dave.fernan...@utoronto.ca (43092.6825) ___ 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: Triggering change notifications when modifying custom object ivars in core data app
On 28-May-09, at 10:39 AM, Keary Suska wrote: On May 28, 2009, at 7:03 AM, Rick Hoge wrote: I have a core data (doc-based) app in which one of the entities includes a custom object as a persistent attribute. The custom object class implements NSCoding, and these objects are saved to the core data store with no problem (they are read back correctly etc). Instance variables of the custom object are exposed in the user interface, and can be edited by the user. The problem I have is that changes to instance variables of these custom objects are not reported to the managed object context, so the core data document is not flagged as dirty and, even if I force a save by adding an entity and invoking save, the modified custom object is not saved (if I quit and reload the old ivar values are loaded). http://developer.apple.com/documentation/Cocoa/Conceptual/CoreData/Articles/cdNSAttributes.html#/ /apple_ref/doc/uid/TP40001919 Thanks - I'd looked at this, and following the information there is what allowed me to insert and display custom object attributes. The documentation shows examples in which an attribute of type NSColor can be set and archived. My problem is that I'm dealing with a complex object type (I have what I think are good reasons for doing this) and I need to flag the context as dirty if an ivar of the custom object is modified. Specifically my entity has a 'transformable' attribute for which the values are a custom object class, and this object class has an ivar that is an NSMutableDictionary. The user can modify entries in this dictionary, and I would like this to cause the context to be flagged as dirty and to have the custom object flagged to be updated in the persistent store. Hope this clarifies things, and thanks again for the suggestion. Rick Keary Suska Esoteritech, Inc. "Demystifying technology for your home or business" (43092.6825) ___ 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
Triggering change notifications when modifying custom object ivars in core data app
I have a core data (doc-based) app in which one of the entities includes a custom object as a persistent attribute. The custom object class implements NSCoding, and these objects are saved to the core data store with no problem (they are read back correctly etc). Instance variables of the custom object are exposed in the user interface, and can be edited by the user. The problem I have is that changes to instance variables of these custom objects are not reported to the managed object context, so the core data document is not flagged as dirty and, even if I force a save by adding an entity and invoking save, the modified custom object is not saved (if I quit and reload the old ivar values are loaded). None of this is terribly surprising, since I'm going outside the core data world with these custom objects. However I expect there must be a way to tell the managed object context it's dirty when a custom object attribute has been modified. I've been reviewing the documentation, but it's not obvious what the preferred/cleanest way would be... I would be most grateful for any suggestions on how to approach this. Regards, Rick ___ 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
Extending supported document types at run time in doc-based app
I would like to implement a plug-in mechanism which will allow a Cocoa document-based application to load plugins which will implement subclasses of NSDocument for different file types. This would allow custom extension of the application to support 3rd party file types, and could have some other advantages. Essentially, this would involve programatically updating the document class information that is usually read from the application's plist file in the CFBundleDocumentTypes entry. I gather that what I want can be achieved by subclassing NSDocumentController and overriding methods like documentClassForType, documentClassNames, etc., but I'm not sure how to indicate things like whether the app is an 'editor' or 'viewer' for a specific document type. If anyone has experience with this kind of approach and can warn of any gotcha's I would be very grateful. Thanks in advance, Rick (43092.6825) ___ 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: [Solved - duh!] Core data storage of objects whose class is loaded from a bundle
Thanks for the replies - it's clear that it's a problem in my NSCoding support (see comment below) On 29-Jan-09, at 5:18 PM, Nick Zitzmann wrote: On Jan 29, 2009, at 2:32 PM, Rick Hoge wrote: -(id)initWithCoder:(NSCoder*)decoder { self = [super initWithCoder:decoder]; // Returns instance of parent class return self; } which was returning an instance of the parent class and not the subclass. Then you've got something strange going on, because initializing the superclass shouldn't be setting the object _to_ the superclass; that's the responsibility of whoever allocated the class to set the class. So either you're allocating the wrong class, or your superclass is doing something unorthodox. It turns out the superclass, which inherits from NSObject, is initializing with [[ParentClass alloc] init] instead of [super initWithCoder:decoder] - perhaps this is the problem... Nick Zitzmann <http://www.chronosnet.com/> (43092.6825) ___ 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: [Solved - duh!] Core data storage of objects whose class is loaded from a bundle
Not surprisingly, the problem had nothing to do with loading the classes via plugins. In my plugin subclasses I was calling -initWithCoder: as follows: -(id)initWithCoder:(NSCoder*)decoder { self = [super initWithCoder:decoder]; // Returns instance of parent class return self; } which was returning an instance of the parent class and not the subclass. After I changed this to the version below, everything worked fine - Core Data encodes and decodes the correct object class - loading the class from a plugin is no problem. -(id)initWithCoder:(NSCoder*)decoder { self = [[MyPluginSubclass alloc] init]; // I know there will be no subclasses [super initWithCoder:decoder]; return self; } On 29-Jan-09, at 3:28 PM, Rick Hoge wrote: I am working on an app in which plugin subclasses are loaded from bundles at launch time (didFinishLaunching in app delegate). The base plugin class is specified in a framework against which the main app is linked. I can create instances of these dynamically loaded subclasses, and assign them as 'transformable' attributes belonging to Core Data entities. During a session the object behaves as expected, and I am able to save the core data store to disk (the plugin base class and dynamicaly loaded subclasses conform to the NSCoding protocol). However when I reload the core data store (i.e. quit the app and open the persistent document again), it seems that Core Data is unarchiving the coded objects as instances of the base plugin class and not the subclass that was (and is again) dynamically loaded. I was hoping that the correct subclass would have been used since the plugins have already been loaded by the app *before* I unarchive the document. I realize that this approach may be 'playing with fire' since weird things will surely happen if some plugins aren't available when the store is re-opened in the future (although this can be handled gracefully I think). I also realize I can just make such attributes 'transient' and manage creation and reloading of the store myself. However it's certainly nice when Core Data does all this stuff for you... I'd hate to introduce complexity just because I was missing something obvious about how to load these attributes. So I was wondering: does anyone know a way to force the correct class to be used when reloading such an attribute? Thanks in advance, Rick ___ 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/rickhoge1%40mac.com This email sent to rickho...@mac.com (43092.6825) ___ 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
Core data storage of objects whose class is loaded from a bundle
I am working on an app in which plugin subclasses are loaded from bundles at launch time (didFinishLaunching in app delegate). The base plugin class is specified in a framework against which the main app is linked. I can create instances of these dynamically loaded subclasses, and assign them as 'transformable' attributes belonging to Core Data entities. During a session the object behaves as expected, and I am able to save the core data store to disk (the plugin base class and dynamicaly loaded subclasses conform to the NSCoding protocol). However when I reload the core data store (i.e. quit the app and open the persistent document again), it seems that Core Data is unarchiving the coded objects as instances of the base plugin class and not the subclass that was (and is again) dynamically loaded. I was hoping that the correct subclass would have been used since the plugins have already been loaded by the app *before* I unarchive the document. I realize that this approach may be 'playing with fire' since weird things will surely happen if some plugins aren't available when the store is re-opened in the future (although this can be handled gracefully I think). I also realize I can just make such attributes 'transient' and manage creation and reloading of the store myself. However it's certainly nice when Core Data does all this stuff for you... I'd hate to introduce complexity just because I was missing something obvious about how to load these attributes. So I was wondering: does anyone know a way to force the correct class to be used when reloading such an attribute? Thanks in advance, Rick ___ 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: Problem assigning image to button under garbage collection
Bill, Rob - Thanks for the replies, and sorry I missed this in the archives. I have googled about such problems, but did not come up with anything. Is there a known issue with images and buttons under GC? Sounds odd.Please file a bug, attaching the application (binary is good enough unless you are comfortable attaching the source). http://bugreporter.apple.com/ This has come up before and has been acknowledged as a bug in the Frameworks. It's apparently harmless (but yes, it's very annoying). http://www.cocoabuilder.com/archive/message/xcode/2007/11/7/16932 The really bad thing about this is that the messages could mask real programming errors... I had made a few changes to my code when I started getting the message, and also had made some cosmetic changes in IB (adding the button image). I wasted a bunch of time reviewing my code changes before realizing it was the button image! I suppose I should still add my voice to the bug reporter. Cheers, Rick ___ 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
Problem assigning image to button under garbage collection
I have a garbage collected app which has been running fine, with no crashing or leaks and passing nicely using the Xray diagnostic tools. A problem arose when I added an NSButton to my nib file and assigned an image to it in Interface Builder (just entering the image name NSAddTemplate) in the Inspector. As soon as I did this, I started getting the following kinds of messages in the log: MyApp (20733,0x100537000) malloc: free_garbage: garbage ptr = 0x8000be360, has non-zero refcount = 1 I tried different approaches to setting the image, such as doing it programatically (keeping a persistent pointer to the image and referring to the button via an IBOutlet). I have googled about such problems, but did not come up with anything. Is there a known issue with images and buttons under GC? Thanks in advance for any info, Rick (43092.6825) ___ 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: Displaying multiple core data relationships in NSOutlineView
Steve, Quincy: Thank you for the replies! At the moment I'm working with a non-Core-Data class to achieve the outline view, using code adapted from the SourceView example. I am realizing that to be able to archive this and correctly maintain object graphs, I'll likely have to link the outlined objects to a Core Data model but have finally resigned myself to the fact that Core Data won't facilitate display in an Outline View. Bindings can spoil you, then you try to do that one thing that isn't straightforward and actually takes code... Cheers, Rick The design I'm trying to achieve is analogous to the way Xcode displays a "Targets" group and a "Bookmarks" group in the same outline view. If Core Data was used for this (and I don't know if it was), it seems clear that Targets and Bookmarks would be modeled as separate to- many relationships and entities, and yet they are nicely displayed in the same outline view. I had to do something a bit more complex than what you want to do: I wanted to summarize results of large numbers of objects into an outline view for a report. In the end I had to create my own hierarchy of summary objects and display them -- which makes sense now but was frustrating realizing that I wouldn't be able to do it with judicious filtering and @summing the raw Core Data objects. You could do the same but your case may be simpler. One possibility would be to make your entities in question descend from a single super class. That super class would only need the outline stuff (parent, children, isLeaf...) and whatever you want to display in the outline, perhaps 'name' (note: avoid calling an attribute 'description' -- binding issues...). Then, I think, you could hack a way to show the whole lot by binding your outline to the super class. Cheers, Steve (43092.6825) ___ 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: Displaying multiple core data relationships in NSOutlineView
Thanks Volker, why don't you have an abstract class that holds the children/parent relationships and make different subclasses for different data types that all inherit from your abstract class. As far as I understand your problem, that should solve it. I have a similar solution working well for me. Ok - this steers me further in the right direction. I think I have been over-complicating this. Are you using Core Data? or just regular Objective-C classes? I am supposing the main advantage of Core Data might be the ability to archive the object graph in a persistent document ... Rick ___ 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
Displaying multiple core data relationships in NSOutlineView
I'm still trying to get my head around how to achieve a particular outline view display by binding an NSTreeController to Core Data entities. I have some test apps running in which, by binding my tree controller to a "root" entity, I can get a nice outline view showing a hierarchy of child entities as long as these descend from the root via a series of to-many relationship with a fixed relationship name (i.e. "children"). Add, remove, and addChild all work as expected. Now comes the messy part. Is there any way to add a hierarchical view of a second hierarchy of to-many relationships descending from the *same* root object in the *same* outline view? (i.e. "children2" ) It would be easy in a second outline view, but I'd like to have both hierarchies shown in a single outline view - one above the other. The design I'm trying to achieve is analogous to the way Xcode displays a "Targets" group and a "Bookmarks" group in the same outline view. If Core Data was used for this (and I don't know if it was), it seems clear that Targets and Bookmarks would be modeled as separate to- many relationships and entities, and yet they are nicely displayed in the same outline view. I'm guessing that this might be achievable by using the same name "children" for the to-many relationships in both hierarchies, and adding a custom "children" accessor method to the root object that returns the appropriate set of entities to show in the outline view. It's not clear to me how this would be set up though. I tried something like the code shown below in a custom "Project" class, for the project entity: -(NSMutableSet*)children { return [NSMutableSet setWithObjects: [self mutableSetValueForKey:@"targets"], [self mutableSetValueForKey:@"bookmarks"], nil]; } but I get the error message 2009-01-16 09:35:02.047 004 ProjectProto[83363:10b] [<_NSNotifyingWrapperMutableSet 0x1057dd0> addObserver:forKeyPath:options:context:] is not supported. Key path: children I have the feeling I'm missing something at a really basic level - if anyone can suggest how to achieve the above design I'd be very grateful. Cheers, Rick ___ 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: Xcode-like "Groups & Files" view: NSTreeController and/or core data?
Hi Douglas, Thanks for the suggestion - I was kind of hoping to hear a vote of confidence for the bindings route. From my experience, I would suggest that you go the route of using NSTreeController along with NSTreeNode. This made life much easier for my heterogeneous dataset. NSTreeNode has a representedObject attribute which you can use to "normalize" the heterogeneous nature of your data. So what I'm trying to figure out now is, what is the "recipe" for designing this? Would the correct order be: 1) design the core data model with entities and relationships 2) programatically populate a source array for the NSTreeController with the display nodes I want 3) set the representedObject of each node to be the appropriate entity I guess steps 2 and 3 are things you wouldn't need if you were just using arrays to display the entities. I think I need to get over the feeling that I can somehow get a nicely populated outline view for "free" with Core data. The AbstractTree tutorial does generate nearly codeless population of an NSOutlineView using bindings from a core data model (but a very simple one). The SourceView tutorial shows a very full-featured example of outline view, although without use of core data. I'd hate to miss out on some smart way of doing this that would get a lot of the view population done with minimal code. Thanks again, Rick ___ 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
Xcode-like "Groups & Files" view: NSTreeController and/or core data?
I have a project in which it would be helpful to create an organizational view for components of a project very similar to the "Groups & Files" view in Xcode. My application would organize pieces of data from a number of experimental sessions, and perform pre- configured sequences of processing operations on these. The datasets could be organized similar to how source code files are done in Xcode, and the processing sequences would be displayed in a way similar to targets and build phases in Xcode. I have dabbled with NSTreeController/NSOutlineView as well as with Core Data, and am trying to decide whether to use NSTreeController or the older datasource/delegate approach to populate my outline view. The thing that is tripping me up, conceptually, is that such an outline view has to represent very different kinds of object - ranging (in Xcode) from build phases to source code files. Do all of these need to be subclasses of some node parent class? or would you use a category? Also in Xcode there are numerous instances where the same object is referenced at different points in the outline view. This seems like it could get messy to me. If anyone can suggest a design strategy that could work well for grouping varied objects type in an NSOutlineView, similar to what's used in Xcode, I'd be very grateful. Thanks, Rick PS it's occurred to me that I could just *use* Xcode for the above tasks, but I should really develop a dedicated interface ... (43092.6825) (43092.6825) ___ 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: Maintaining mutable values with NSDictionaryControllerKeyValuePair
I pulled my hair out over this one, but I finally found an acceptable workaround, although it doesn't solve the fundamental problem of NSDictionaryController. Thanks very much for the reply and workaround. I will explore this solution further. The NSDictionaryController/bindings route seems to work fine if you have a simple mutable dictionary in which the keys are strings and the values are discrete objects like NSStrings or NSNumbers. Then you can edit the values with no problem. It just seems to get difficult when the dictionary values are themselves collections. I could live with this I suppose, in cases where read-only display of the dictionary was the primary goal. However it would really be nice to be able to edit the contents of collections, and the present limitations should really be mentioned in the documentation (maybe the current docs say so in some obtuse way, but if so I didn't catch it). After considering this problem some more, it seems like in my case the easiest workaround is to abandon the idea of having a dictionary of dictionaries and instead use an NSArray (or NSSet) of dictionaries. This will avoid the use of mysterious immutable proxy dictionaries by NSDictionaryController and should deliver equivalent functionality. Originally I was attracted by the simplicity of obtaining a list of entries using allKeys, and addressing the entries by name, but similar functionality could be obtained with other connection objects using predicates (with a bit more complexity). Would still be sweet if NSDictionaryController provided deeper read- write access to embedded dictionaries, but I won't hold my breath. Thanks again, Rick ___ 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: Maintaining mutable values with NSDictionaryControllerKeyValuePair
I pulled my hair out over this one, but I finally found an acceptable workaround, although it doesn't solve the fundamental problem of NSDictionaryController. Thanks very much for the reply and workaround. I will explore this solution further. The NSDictionaryController/bindings route seems to work fine if you have a simple mutable dictionary in which the keys are strings and the values are discrete objects like NSStrings or NSNumbers. Then you can edit the values with no problem. It just seems to get difficult when the dictionary values are themselves collections. I could live with this I suppose, in cases where read-only display of the dictionary was the primary goal. However it would really be nice to be able to edit the contents of collections, and the present limitations should really be mentioned in the documentation (maybe the current docs say so in some obtuse way, but if so I didn't catch it). Thanks again, Rick ___ 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: Maintaining mutable values with NSDictionaryControllerKeyValuePair
I'm using an NSDictionaryController object to control the data provided to an NSTableView object. I'm attempting to use key-value coding through the dictionary controller to manipulate the data in a bindings-compatible way, by calling the method -arrangedObjects on the NSDictionaryController, and then manipulating the NSDictionaryControllerKeyValuePairs that this method returns in an array. Any luck? I am having a similar problem - mutable dictionary objects that are themselves stored in a dictionary will be presented as immutable dictionaries by the NSDictionaryController. This makes it impossible to bind controls to keypaths that drill into dictionaries below the level of the outermost container. i.e. even if arrangedObjects.value should point to a mutable dictionary, attempts to edit arrangedObjects.value.someKey via a UI control will generate the following error: *** -[NSCFDictionary setObject:forKey:]: mutating method sent to immutable object Having a workaround for this would be really nice - has anyone found one? I will file a bug as I don't think this is the behavior most would expect. This is turning something that would have "just worked" in about fifteen minutes into yet another quest for a messy workaround... Thanks in advance, Rick ___ 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: Use of AppKit in command-line app on headless node
Thanks again for that very detailed post - I know it sounds like I'm being lazy, but there are other parts of the app that would have to be redesigned to allow the possibility for code use under headless conditions and it's really important to me to know why this is necessary. What you said goes a long way toward clarifying the underlying issues. Obviously I'm not going to risk it now. ... One obvious alternative is to create a 'Data Object' class that has no AppKit dependencies and stash it as an instance variable in a 'thin' NSDocument subclass that just supports tasks relating to a real document-based app in a window server environment. To make my app work, I need two layers of subclass for my documents (a general NSDocument subclass and several subclasses of this for specific data types) so it's a bit more tricky. I'd need to have a data object class hierarchy and a parallel document hierarchy. If all of the smarts are in your own custom classes, why do you need a hierarchy of NSDocument subclasses? Have a single NSDocument subclass that passes all of the important methods on to your custom classes, and your job should be done. The way the app was originally designed, the top level NSDocument subclass implements custom functionalities used by all document types. There are a few different types of document/data that are related, but different enough that it has worked well to use separate subclasses to implement them. For example different nib files are loaded depending on the document type (something that would go in the NSDocument subclass), and the data model is different (something which would go in the data object class). Rick Mike ___ 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/rickhoge1%40mac.com This email sent to [EMAIL PROTECTED] (43092.6825) ___ 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 [EMAIL PROTECTED]
Re: Use of AppKit in command-line app on headless node
Thanks for the replies - just got them now as my MobileMe email went offline for some reason last night... I noticed that there is some useful info relating to this topic in the documentation on Agents and Daemons at http://developer.apple.com/technotes/tn2005/tn2083.html#SECLIVINGDANGEROUSLY It does say that AppKit is not daemon-safe, but my testing suggests that if (as suggested in the technote) you avoid sensitive methods it should be ok (more info would be welcome). I'm curious as to whether you really read the thing I did, I did! (really) The fact that some discussion of possible issues *is* provided came of as sort of a tacit approval that in some cases this approach might be appropriate. To me it comes down to what *methods* you expect to work...I certainly wouldn't expect to be able to instantiate an NSDocumentController and create and manage documents with it in an environment with no window server. However if my NSDocument subclass contains a set of ivars (none of which use AppKit classes) that constitute a useful data model and implements file IO routines that do not, in any way, depend on the window server, document controller, or any AppKit classes, it seems reasonable to expect that this subset of functionality could be used even on a headless node. I can see how image decompression routines might be fragile, but the usage case I'm describing is a little different. One obvious alternative is to create a 'Data Object' class that has no AppKit dependencies and stash it as an instance variable in a 'thin' NSDocument subclass that just supports tasks relating to a real document-based app in a window server environment. To make my app work, I need two layers of subclass for my documents (a general NSDocument subclass and several subclasses of this for specific data types) so it's a bit more tricky. I'd need to have a data object class hierarchy and a parallel document hierarchy. If multiple inheritance was supported in Objective-C, it would be a bit simpler as I could create parent classes for data document objects and then multiply inherit the required parent classes in the document- base app (or just use the Foundation-based data object classes in headless situations). I suppose the alternative described above is one of the standard workarounds for multiple inheritance in Obj-C. So the appropriate question to have asked may well be "what class structure will work well to factor out data model and NSDocument functionality so that the data model can be safely used in a headless context". Keep in mind that the only posts I could find on this were ones suggesting workarounds for use of NSImage, with the caveats noted above. Now, the consensus I'm hearing is "don't do it" , which will help me justify the (slightly) increased complexity required for this. Rick "A routine might behave differently depending on its input parameters. For example, an image decompression routine might work for some types of images and fail for others." "The behavior of any given framework, and the routines within that framework, can change from release-to-release." In other words, you're playing with fire in a gasoline-soaked shed. Just because you haven't been burned horribly *yet* doesn't mean you won't be. AppKit requires a window server connection, full stop. To the extent that it functions without one, this behavior is unsupported, unreliable, and highly risky. Don't do it. In case you didn't know, having a window server connection isn't the same as being a GUI app, however. You just need to be able to connect to it. Realistically, this means either having a user who's logged in to the GUI and always running as that user, or running as root and not logging in or out. And lastly, as far as I know you must initialize NSApplication before touching AppKit in any other way. Like the window server requirement, you may be able to get away without doing it sometimes but you should never rely on it. Mike ___ 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/rickhoge1%40mac.com This email sent to [EMAIL PROTECTED] (43092.6825) ___ 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 [EMAIL PROTECTED]
Re: Use of AppKit in command-line app on headless node
I am trying to factor some frameworks so that code used in a document-based Cocoa app can be shared with command-line tools that might run on a headless node (no window server). I've seen some discussion in the past on questions such as whether NSImage and related classes can be used headless. It seems that this works, but it's necessary to initialize and NSApplication instance for the classes to work correctly. I noticed that there is some useful info relating to this topic in the documentation on Agents and Daemons at http://developer.apple.com/technotes/tn2005/tn2083.html#SECLIVINGDANGEROUSLY It does say that AppKit is not daemon-safe, but my testing suggests that if (as suggested in the technote) you avoid sensitive methods it should be ok (more info would be welcome). I should also mention that the code in question would potentially be run under Xgrid - have not tested this yet; wonder if there could be bootstrap namespace issues here... Rick ___ 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 [EMAIL PROTECTED]
Use of AppKit in command-line app on headless node
Hi - I am trying to factor some frameworks so that code used in a document- based Cocoa app can be shared with command-line tools that might run on a headless node (no window server). I've seen some discussion in the past on questions such as whether NSImage and related classes can be used headless. It seems that this works, but it's necessary to initialize and NSApplication instance for the classes to work correctly. I realize that many AppKit functions will not be meaningful in a headless context. However I am wondering if, for example, it would be possible (and safe) to use an NSDocument subclass instance in the following way in a headless app: MyDocument *doc = [[[MyDocument] alloc] init]; [doc readFromURL:url ofType:type error:error]; The idea would simply be to use the instance as a container for some data, and use the file read and write methods I've already implemented for the doc-based interactive application. This seems to work in some simple test apps I've written, but I'm wondering if there is anything risky about this that could become a problem in the future. Also, when is it necessary to initialize an NSApplication instance? Is this just an NSImage thing? or is it a more general AppKit requirement. Thanks for any suggestions, Rick ___ 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 [EMAIL PROTECTED]
Re: Automatic population of NSTableView with custom columns at launch time
More observations on this - Unfortunately, I'm out of ideas; these were mainly off the top of my head. Without seeing your specific source code, I can't offer any more suggestions -- it is quite possible something else is wrong (ie: the identifier isn't set). The identifier is definitely set in the columns I'm adding. You probably want to debug the app to find out why/when your columns are being removed, and go from there. You can try breaking on the internal tableview methods, _readPersistentTableColumns and _writePersistentTableColumns, however, these methods are purely internal, and may be removed in future releases. In other words, don't call them or override them. I made an NSTableView subclass with overrides of these internal methods (just calling super) and noticed the following things: - _writePersistentTaboleColumns is called when a column is resized, but *not* when a column is added - if I force a call to the above method by resizing a column, a call to [self tableColumns] includes columns added in code - if I quite and relaunch, _readPersistentTableColumns is called but after sending the same message to super the table still contains only the nib columns Rick You are correct, step #3 shouldn't be required. If all else fails, you may have to hand-roll a solution where you don't use the tableview logic, and store out the widths/table columns yourself. -corbin I set autoSaveFileName to nil in the nib file, then do the following in my code: 1) add the new table columns (addTableColumn: etc.) 2) call setAutosaveName:@"someFile" , call setAutosaveTableColumns:YES 3) manually change width of table column in UI just in case this will force an autosave 4) quit app On next launch, the column I added in step 1 is not there. Changes to width of columns defined in the nib are preserved though. Also is step 3 really needed to force an autosave? Ideally the added columns would have to be 'remembered' even if the user does not resize any... thanks for the suggestions, though! Rick On 4-Aug-08, at 7:05 PM, Corbin Dunn wrote: Are you calling setAutosaveName: yourself? Set it to nil in the nib. Then, call it yourself. Before you call it, print out all the table columns to see what they are. Then, load your tablecolumns that you want (add new ones). Then call setAutosaveName:. Change the width of a column in your GUI. This should save out the autosave values. Quit your app. Restart it. Are the columns restored? This pattern should work; I use it internally in the open and save panel. corbin On Aug 4, 2008, at 3:36 PM, Rick Hoge wrote: Thanks for the suggestion - I tried calling setAutosaveTableColumns: after adding a column from code, but on next launch it only showed the columns that are defined in the nib with IB. Rick On 4-Aug-08, at 5:39 PM, Corbin Dunn wrote: If you add all the columns (and remove old ones) before calling setAutosaveName:, or setAutosaveTableColumns:, then it should work out okay; it will restore all of the widths, positions, etc. corbin On Aug 4, 2008, at 2:03 PM, Rick Hoge wrote: I'm working on an application that will allow users to add columns of descriptive information to an NSTableView - the available columns are determined at launch time by loading a dictionary. In my test app, I can add columns to my table no problem. Now I am trying to decide on a robust and efficient way to make sure that the set of columns chosen by the user, and their geometry, is saved when quitting the app and restored at the next launch. I can think of a number of brute force ways to do it - save an array of column identifiers and/or value bindings to user preferences, for example. I know it's possible to autosave column layout information under Leopard through the framework, and this appears to work. The autosave info appears to restore the geometry of columns defined in the nib file, but it won't force a reload of columns created programatically in the last session. I suspect that the autosave file may actually contain the identifiers of all columns displayed as of the last application quit, and wonder if there is a way, during nib loading, to access this list so I can initialize the table. I don't like having the same information stored multiple places (i.e. my own NSArray in user prefs replicating info that might be more complete in the NSTableView autosave file) if I can avoid it, but can't seem to find a way to get at all the info in this file. If anyone has some good examples of how this can be done, or some past experience to share on what works well, I'd be very grateful. (43092.6825) (43092.6825) (43092.6825) ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do
Re: Automatic population of NSTableView with custom columns at launch time
One other thing I'm not sure I understand - Are you calling setAutosaveName: yourself? Set it to nil in the nib. Then, call it yourself. Why can't this be set in the nib? I would have thought this is the logical place to set it, and that once set any changes to the table would be recorded. What happens differently when the values (autosave and file name) are set in the code? Thanks again for the reply and sorry if this is dense - just trying to make sure I understand the suggestions. Rick Before you call it, print out all the table columns to see what they are. Then, load your tablecolumns that you want (add new ones). Then call setAutosaveName:. Change the width of a column in your GUI. This should save out the autosave values. Quit your app. Restart it. Are the columns restored? This pattern should work; I use it internally in the open and save panel. corbin On Aug 4, 2008, at 3:36 PM, Rick Hoge wrote: Thanks for the suggestion - I tried calling setAutosaveTableColumns: after adding a column from code, but on next launch it only showed the columns that are defined in the nib with IB. Rick On 4-Aug-08, at 5:39 PM, Corbin Dunn wrote: If you add all the columns (and remove old ones) before calling setAutosaveName:, or setAutosaveTableColumns:, then it should work out okay; it will restore all of the widths, positions, etc. corbin On Aug 4, 2008, at 2:03 PM, Rick Hoge wrote: I'm working on an application that will allow users to add columns of descriptive information to an NSTableView - the available columns are determined at launch time by loading a dictionary. In my test app, I can add columns to my table no problem. Now I am trying to decide on a robust and efficient way to make sure that the set of columns chosen by the user, and their geometry, is saved when quitting the app and restored at the next launch. I can think of a number of brute force ways to do it - save an array of column identifiers and/or value bindings to user preferences, for example. I know it's possible to autosave column layout information under Leopard through the framework, and this appears to work. The autosave info appears to restore the geometry of columns defined in the nib file, but it won't force a reload of columns created programatically in the last session. I suspect that the autosave file may actually contain the identifiers of all columns displayed as of the last application quit, and wonder if there is a way, during nib loading, to access this list so I can initialize the table. I don't like having the same information stored multiple places (i.e. my own NSArray in user prefs replicating info that might be more complete in the NSTableView autosave file) if I can avoid it, but can't seem to find a way to get at all the info in this file. If anyone has some good examples of how this can be done, or some past experience to share on what works well, I'd be very grateful. (43092.6825) (43092.6825) ___ 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 [EMAIL PROTECTED]
Re: Automatic population of NSTableView with custom columns at launch time
Hmmm. Does not seem to be doing it. Unfortunately, I'm out of ideas; these were mainly off the top of my head. Without seeing your specific source code, I can't offer any more suggestions -- it is quite possible something else is wrong (ie: the identifier isn't set). You probably want to debug the app to find out why/when your columns are being removed, and go from there. You can try breaking on the internal tableview methods, _readPersistentTableColumns and _writePersistentTableColumns, however, these methods are purely internal, and may be removed in future releases. In other words, don't call them or override them. The more I google on this, the more it looks like many people have had the same problem without ever getting resolved. I've filed a bug report (6125547). The other weird thing is that I can't find the file autosave file (which I called "MyDocTableInfo") anywhere. I thought that if I could locate this file and query the property list I might get some idea of what's going on. However it's nowhere that I can find (neither with Spotlight, manual searching, or ls -R | grep MyDocTableInfo). Seems like there needs to be more documentation on this, and that the functionality could be enhanced. If it did what I thought it would do (restoring all columns, including those created programatically) it would be amazing. Manual tracking of columns could easily get *very* messy... I don't see why columns added through code couldn't be autosaved - all the information provided for nib-defined columns is available. Rick Thanks anyway - Of course it never hurts to actually show some code (in case this might prompt an idea). This is a test method that adds a column and then sets the autosave info - I wouldn't actually use it this way, but for testing it does the steps in the suggested order. -(IBAction)addTableColumnTest:(id)sender { // documentTable is an IBOutlet // autoSaveTableName: is empty in the nib // Get existing column to copy some formatting info NSTableColumn *prototypeColumn = [[documentTable tableColumns] lastObject]; // Create and add the new column NSTableColumn *newColumn = [[NSTableColumn alloc] initWithIdentifier:@"comments"]; // app is GC [[newColumn headerCell] setStringValue:@"Comments"]; // Assign header text [[newColumn dataCell] setFont:[[prototypeColumn dataCell] font]]; // Copy font from existing table column [newColumn bind:@"value" toObject:documentArrayController withKeyPath:@"arrangedObjects.comments" options:nil]; [documentTable addTableColumn:newColumn]; // Set the autoSave info [documentTable setAutosaveTableColumns:YES]; [documentTable setAutosaveName:@"MyDocTableInfo"]; } You are correct, step #3 shouldn't be required. If all else fails, you may have to hand-roll a solution where you don't use the tableview logic, and store out the widths/table columns yourself. -corbin I set autoSaveFileName to nil in the nib file, then do the following in my code: 1) add the new table columns (addTableColumn: etc.) 2) call setAutosaveName:@"someFile" , call setAutosaveTableColumns:YES 3) manually change width of table column in UI just in case this will force an autosave 4) quit app On next launch, the column I added in step 1 is not there. Changes to width of columns defined in the nib are preserved though. Also is step 3 really needed to force an autosave? Ideally the added columns would have to be 'remembered' even if the user does not resize any... thanks for the suggestions, though! Rick On 4-Aug-08, at 7:05 PM, Corbin Dunn wrote: Are you calling setAutosaveName: yourself? Set it to nil in the nib. Then, call it yourself. Before you call it, print out all the table columns to see what they are. Then, load your tablecolumns that you want (add new ones). Then call setAutosaveName:. Change the width of a column in your GUI. This should save out the autosave values. Quit your app. Restart it. Are the columns restored? This pattern should work; I use it internally in the open and save panel. corbin On Aug 4, 2008, at 3:36 PM, Rick Hoge wrote: Thanks for the suggestion - I tried calling setAutosaveTableColumns: after adding a column from code, but on next launch it only showed the columns that are defined in the nib with IB. Rick On 4-Aug-08, at 5:39 PM, Corbin Dunn wrote: If you add all the columns (and remove old ones) before calling setAutosaveName:, or setAutosaveTableColumns:, then it should work out okay; it will restore all of the widths, positions, etc. corbin On Aug 4, 2008, at 2:03 PM, Rick Hoge wrote: I'm working on an application that will allow users to add columns of descriptive information to an NSTableView - the available columns
Re: Automatic population of NSTableView with custom columns at launch time
Also, let me step back for a moment and recommend another approach. Ideally, if you know all possible permutations of the columns that the user could ever want, then just add them all at design time in the nib, and hide (setHidden:YES) the ones you initially want hidden. Then, add a pop on the header to hide/unhiden individual columns. That is the ideal way to do this. Granted, I realize all table columns can't always be known at design time (ie: populating them from a SQL database, or whatever other logic). I'd seen mention of the fact that it's better to define 'known' columns in the nib and use hide/unhide to control display - thanks for confirming that this is indeed a recommended practice. Unfortunately I have a combination of known columns (comments, path) and other stuff that isn't known until launch time (a dictionary is loaded and could have hundreds of possible pieces of information, of which a user would typically select some small number). So I'm stuck supporting at least part of the table structure programatically. Rick corbin On Aug 4, 2008, at 5:31 PM, Rick Hoge wrote: Hmmm. Does not seem to be doing it. Unfortunately, I'm out of ideas; these were mainly off the top of my head. Without seeing your specific source code, I can't offer any more suggestions -- it is quite possible something else is wrong (ie: the identifier isn't set). You probably want to debug the app to find out why/when your columns are being removed, and go from there. You can try breaking on the internal tableview methods, _readPersistentTableColumns and _writePersistentTableColumns, however, these methods are purely internal, and may be removed in future releases. In other words, don't call them or override them. Thanks anyway - Of course it never hurts to actually show some code (in case this might prompt an idea). This is a test method that adds a column and then sets the autosave info - I wouldn't actually use it this way, but for testing it does the steps in the suggested order. -(IBAction)addTableColumnTest:(id)sender { // documentTable is an IBOutlet // autoSaveTableName: is empty in the nib // Get existing column to copy some formatting info NSTableColumn *prototypeColumn = [[documentTable tableColumns] lastObject]; // Create and add the new column NSTableColumn *newColumn = [[NSTableColumn alloc] initWithIdentifier:@"comments"]; // app is GC [[newColumn headerCell] setStringValue:@"Comments"]; // Assign header text [[newColumn dataCell] setFont:[[prototypeColumn dataCell] font]]; // Copy font from existing table column [newColumn bind:@"value" toObject:documentArrayController withKeyPath:@"arrangedObjects.comments" options:nil]; [documentTable addTableColumn:newColumn]; // Set the autoSave info [documentTable setAutosaveTableColumns:YES]; [documentTable setAutosaveName:@"MyDocTableInfo"]; } You are correct, step #3 shouldn't be required. If all else fails, you may have to hand-roll a solution where you don't use the tableview logic, and store out the widths/table columns yourself. -corbin I set autoSaveFileName to nil in the nib file, then do the following in my code: 1) add the new table columns (addTableColumn: etc.) 2) call setAutosaveName:@"someFile" , call setAutosaveTableColumns:YES 3) manually change width of table column in UI just in case this will force an autosave 4) quit app On next launch, the column I added in step 1 is not there. Changes to width of columns defined in the nib are preserved though. Also is step 3 really needed to force an autosave? Ideally the added columns would have to be 'remembered' even if the user does not resize any... thanks for the suggestions, though! Rick On 4-Aug-08, at 7:05 PM, Corbin Dunn wrote: Are you calling setAutosaveName: yourself? Set it to nil in the nib. Then, call it yourself. Before you call it, print out all the table columns to see what they are. Then, load your tablecolumns that you want (add new ones). Then call setAutosaveName:. Change the width of a column in your GUI. This should save out the autosave values. Quit your app. Restart it. Are the columns restored? This pattern should work; I use it internally in the open and save panel. corbin On Aug 4, 2008, at 3:36 PM, Rick Hoge wrote: Thanks for the suggestion - I tried calling setAutosaveTableColumns: after adding a column from code, but on next launch it only showed the columns that are defined in the nib with IB. Rick On 4-Aug-08, at 5:39 PM, Corbin Dunn wrote: If you add all the columns (and remove old ones) before calling setAutosaveName:, or setAutosaveTableColumns:, then it should work out okay; it will restore all of the widths, positions, etc. corbin On Aug 4,
Re: Automatic population of NSTableView with custom columns at launch time
Hmmm. Does not seem to be doing it. Unfortunately, I'm out of ideas; these were mainly off the top of my head. Without seeing your specific source code, I can't offer any more suggestions -- it is quite possible something else is wrong (ie: the identifier isn't set). You probably want to debug the app to find out why/when your columns are being removed, and go from there. You can try breaking on the internal tableview methods, _readPersistentTableColumns and _writePersistentTableColumns, however, these methods are purely internal, and may be removed in future releases. In other words, don't call them or override them. Thanks anyway - Of course it never hurts to actually show some code (in case this might prompt an idea). This is a test method that adds a column and then sets the autosave info - I wouldn't actually use it this way, but for testing it does the steps in the suggested order. -(IBAction)addTableColumnTest:(id)sender { // documentTable is an IBOutlet // autoSaveTableName: is empty in the nib // Get existing column to copy some formatting info NSTableColumn *prototypeColumn = [[documentTable tableColumns] lastObject]; // Create and add the new column NSTableColumn *newColumn = [[NSTableColumn alloc] initWithIdentifier:@"comments"]; // app is GC [[newColumn headerCell] setStringValue:@"Comments"]; // Assign header text [[newColumn dataCell] setFont:[[prototypeColumn dataCell] font]]; // Copy font from existing table column [newColumn bind:@"value" toObject:documentArrayController withKeyPath:@"arrangedObjects.comments" options:nil]; [documentTable addTableColumn:newColumn]; // Set the autoSave info [documentTable setAutosaveTableColumns:YES]; [documentTable setAutosaveName:@"MyDocTableInfo"]; } You are correct, step #3 shouldn't be required. If all else fails, you may have to hand-roll a solution where you don't use the tableview logic, and store out the widths/table columns yourself. -corbin I set autoSaveFileName to nil in the nib file, then do the following in my code: 1) add the new table columns (addTableColumn: etc.) 2) call setAutosaveName:@"someFile" , call setAutosaveTableColumns:YES 3) manually change width of table column in UI just in case this will force an autosave 4) quit app On next launch, the column I added in step 1 is not there. Changes to width of columns defined in the nib are preserved though. Also is step 3 really needed to force an autosave? Ideally the added columns would have to be 'remembered' even if the user does not resize any... thanks for the suggestions, though! Rick On 4-Aug-08, at 7:05 PM, Corbin Dunn wrote: Are you calling setAutosaveName: yourself? Set it to nil in the nib. Then, call it yourself. Before you call it, print out all the table columns to see what they are. Then, load your tablecolumns that you want (add new ones). Then call setAutosaveName:. Change the width of a column in your GUI. This should save out the autosave values. Quit your app. Restart it. Are the columns restored? This pattern should work; I use it internally in the open and save panel. corbin On Aug 4, 2008, at 3:36 PM, Rick Hoge wrote: Thanks for the suggestion - I tried calling setAutosaveTableColumns: after adding a column from code, but on next launch it only showed the columns that are defined in the nib with IB. Rick On 4-Aug-08, at 5:39 PM, Corbin Dunn wrote: If you add all the columns (and remove old ones) before calling setAutosaveName:, or setAutosaveTableColumns:, then it should work out okay; it will restore all of the widths, positions, etc. corbin On Aug 4, 2008, at 2:03 PM, Rick Hoge wrote: I'm working on an application that will allow users to add columns of descriptive information to an NSTableView - the available columns are determined at launch time by loading a dictionary. In my test app, I can add columns to my table no problem. Now I am trying to decide on a robust and efficient way to make sure that the set of columns chosen by the user, and their geometry, is saved when quitting the app and restored at the next launch. I can think of a number of brute force ways to do it - save an array of column identifiers and/or value bindings to user preferences, for example. I know it's possible to autosave column layout information under Leopard through the framework, and this appears to work. The autosave info appears to restore the geometry of columns defined in the nib file, but it won't force a reload of columns created programatically in the last session. I suspect that the autosave file may actually contain the identifiers of all columns displayed as of the last application quit, and wonder if there is a way, during nib loading, to access
Re: Automatic population of NSTableView with custom columns at launch time
Hmmm. Does not seem to be doing it. I set autoSaveFileName to nil in the nib file, then do the following in my code: 1) add the new table columns (addTableColumn: etc.) 2) call setAutosaveName:@"someFile" , call setAutosaveTableColumns:YES 3) manually change width of table column in UI just in case this will force an autosave 4) quit app On next launch, the column I added in step 1 is not there. Changes to width of columns defined in the nib are preserved though. Also is step 3 really needed to force an autosave? Ideally the added columns would have to be 'remembered' even if the user does not resize any... thanks for the suggestions, though! Rick On 4-Aug-08, at 7:05 PM, Corbin Dunn wrote: Are you calling setAutosaveName: yourself? Set it to nil in the nib. Then, call it yourself. Before you call it, print out all the table columns to see what they are. Then, load your tablecolumns that you want (add new ones). Then call setAutosaveName:. Change the width of a column in your GUI. This should save out the autosave values. Quit your app. Restart it. Are the columns restored? This pattern should work; I use it internally in the open and save panel. corbin On Aug 4, 2008, at 3:36 PM, Rick Hoge wrote: Thanks for the suggestion - I tried calling setAutosaveTableColumns: after adding a column from code, but on next launch it only showed the columns that are defined in the nib with IB. Rick On 4-Aug-08, at 5:39 PM, Corbin Dunn wrote: If you add all the columns (and remove old ones) before calling setAutosaveName:, or setAutosaveTableColumns:, then it should work out okay; it will restore all of the widths, positions, etc. corbin On Aug 4, 2008, at 2:03 PM, Rick Hoge wrote: I'm working on an application that will allow users to add columns of descriptive information to an NSTableView - the available columns are determined at launch time by loading a dictionary. In my test app, I can add columns to my table no problem. Now I am trying to decide on a robust and efficient way to make sure that the set of columns chosen by the user, and their geometry, is saved when quitting the app and restored at the next launch. I can think of a number of brute force ways to do it - save an array of column identifiers and/or value bindings to user preferences, for example. I know it's possible to autosave column layout information under Leopard through the framework, and this appears to work. The autosave info appears to restore the geometry of columns defined in the nib file, but it won't force a reload of columns created programatically in the last session. I suspect that the autosave file may actually contain the identifiers of all columns displayed as of the last application quit, and wonder if there is a way, during nib loading, to access this list so I can initialize the table. I don't like having the same information stored multiple places (i.e. my own NSArray in user prefs replicating info that might be more complete in the NSTableView autosave file) if I can avoid it, but can't seem to find a way to get at all the info in this file. If anyone has some good examples of how this can be done, or some past experience to share on what works well, I'd be very grateful. (43092.6825) (43092.6825) ___ 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 [EMAIL PROTECTED]
Re: Automatic population of NSTableView with custom columns at launch time
Thanks for the suggestion - I tried calling setAutosaveTableColumns: after adding a column from code, but on next launch it only showed the columns that are defined in the nib with IB. Rick On 4-Aug-08, at 5:39 PM, Corbin Dunn wrote: If you add all the columns (and remove old ones) before calling setAutosaveName:, or setAutosaveTableColumns:, then it should work out okay; it will restore all of the widths, positions, etc. corbin On Aug 4, 2008, at 2:03 PM, Rick Hoge wrote: I'm working on an application that will allow users to add columns of descriptive information to an NSTableView - the available columns are determined at launch time by loading a dictionary. In my test app, I can add columns to my table no problem. Now I am trying to decide on a robust and efficient way to make sure that the set of columns chosen by the user, and their geometry, is saved when quitting the app and restored at the next launch. I can think of a number of brute force ways to do it - save an array of column identifiers and/or value bindings to user preferences, for example. I know it's possible to autosave column layout information under Leopard through the framework, and this appears to work. The autosave info appears to restore the geometry of columns defined in the nib file, but it won't force a reload of columns created programatically in the last session. I suspect that the autosave file may actually contain the identifiers of all columns displayed as of the last application quit, and wonder if there is a way, during nib loading, to access this list so I can initialize the table. I don't like having the same information stored multiple places (i.e. my own NSArray in user prefs replicating info that might be more complete in the NSTableView autosave file) if I can avoid it, but can't seem to find a way to get at all the info in this file. If anyone has some good examples of how this can be done, or some past experience to share on what works well, I'd be very grateful. (43092.6825) ___ 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 [EMAIL PROTECTED]
Automatic population of NSTableView with custom columns at launch time
I'm working on an application that will allow users to add columns of descriptive information to an NSTableView - the available columns are determined at launch time by loading a dictionary. In my test app, I can add columns to my table no problem. Now I am trying to decide on a robust and efficient way to make sure that the set of columns chosen by the user, and their geometry, is saved when quitting the app and restored at the next launch. I can think of a number of brute force ways to do it - save an array of column identifiers and/or value bindings to user preferences, for example. I know it's possible to autosave column layout information under Leopard through the framework, and this appears to work. The autosave info appears to restore the geometry of columns defined in the nib file, but it won't force a reload of columns created programatically in the last session. I suspect that the autosave file may actually contain the identifiers of all columns displayed as of the last application quit, and wonder if there is a way, during nib loading, to access this list so I can initialize the table. I don't like having the same information stored multiple places (i.e. my own NSArray in user prefs replicating info that might be more complete in the NSTableView autosave file) if I can avoid it, but can't seem to find a way to get at all the info in this file. If anyone has some good examples of how this can be done, or some past experience to share on what works well, I'd be very grateful. Thanks! Rick ___ 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 [EMAIL PROTECTED]
Re: Xcode style divider with embedded popup and pulldown menus
Thanks for the replies - seems like a custom view and possibly NSMatrix will do the job. Rick On 18-Jul-08, at 12:38 PM, Chris Hanson wrote: On Jul 18, 2008, at 8:39 AM, Rick Hoge wrote: I expect this is a custom class created by Apple - does anyone know of an efficient way to replicate this type of view? One thought I had was to create a table with a single row and add the desired controls as cells. Just create a view and add sub-views to it to do what you want. There's no reason to worry about trying to use a single-row table with cells and so on -- views will be sufficient for what you want to do. -- Chris (43092.6825) ___ 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 [EMAIL PROTECTED]
Xcode style divider with embedded popup and pulldown menus
I would like to include a view divider similar to the one used in Xcode at the top of the editor window (contains forward and back buttons, popups for selection of source file and function, as well as pulldowns for a number of functions). I expect this is a custom class created by Apple - does anyone know of an efficient way to replicate this type of view? One thought I had was to create a table with a single row and add the desired controls as cells. Any suggestions would be greatly appreciated - Rick (43092.6825) ___ 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 [EMAIL PROTECTED]
[Job Posting] Openings for students and/or post-doc in medical imaging lab, Montreal Canada
Hi - I have openings for students and one post-doc in my lab at the University of Montreal. We develop MRI and optical imaging techniques for characterizing how the brain works, as well as a number of Cocoa- based analysis and visualization tools. We are funded by the Canadian Institutes of Health Research and the Canadian Foundation for Innovation to study changes in brain physiology during aging, as well as the effects of cardiovascular health and fitness on cognitive function. Student and post-doc research projects will be related to technology development in support of these themes in a rich interdisciplinary environment. Given the importance of the Mac platform and Cocoa in my lab, I thought I would post these openings in cocoa-dev. Here are some of the requirements: Student: - must be functional in French and English; course work is given in French, with language instruction offered to non-francophones - meet admission criteria for Master's or Ph.D. in biomedical engineering at Université de Montréal - interested in MRI, neuroscience, image processing, and biomedical research - experience in MRI an asset, particularly pulse-sequence development on Siemens platforms - experience in Mac development, particularly Cocoa, is an asset - experience in Matlab an asset - strong background in statistics an asset Post-doc: - should be fluent in English (French an asset, but not mandatory for post-doc) - possess a Ph.D. in a field related to biomedical science or engineering - interested in MRI, neuroscience, image processing, and biomedical research - experience in MRI an asset, particularly pulse-sequence development on Siemens platforms - experience in Mac development, particularly Cocoa, is an asset - experience in Matlab an asset - strong background in statistics an asset Qualified applicants would be eligible for student or post-doc salaries at the standard levels of our institution, which generally support quite a decent standard of living in Montreal (a really great place to be a student!) The starting time frame is somewhat flexible. For more information about our lab, and some related projects, visit http://unfweb.criugm.qc.ca/rhoge/ http://www.neurolens.org/ or contact me offline at the email address used for this post. Best, Rick Hoge ___ 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 [EMAIL PROTECTED]
Re: Problem with cblas_sgemm in 64 bit build
As usual I'm sure it will turn out to be some silly small thing (and not a mysterious alignment issue with CBLAS). The strange thing is that the problem only arises when the matrices involved exceed a certain size. After further testing with simplified test cases, I think it actually is a bug in the CBLAS function cblas_sgemm that pops up in 64-bit builds. I filed it (bug id 5988197). Searching the lists.apple.com archives I did not find very many mentions of CBLAS or this function - I posted a more detailed description of my tests, with sample code, in perfoptimization-dev (which seems to have very low traffic). As a workaround, I'm using the double-precision version cblas_dgemm, which works fine (although it's not really what I want). Rick Rick On 4-Jun-08, at 2:08 PM, Kyle Sluder wrote: Take a look at NSInteger and CGFloat, and the 64-Bit Transition Guide for Cocoa: http://developer.apple.com/documentation/Cocoa/Conceptual/Cocoa64BitGuide/ConvertingExistingApp/chapter_4_section_3.html --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/rickhoge1%40mac.com This email sent to [EMAIL PROTECTED] ___ 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 [EMAIL PROTECTED]
Re: Problem with cblas_sgemm in 64 bit build
Thanks for the suggestions - I had already scoured the 64-bit transition guide, and didn't think I needed to use NSInteger and CGFloat since integers and floats appear to be the same size for both 32 and 64 bit builds. Just to be sure though, I tried replacing any int and float declarations touching this code with NSInteger and CGFloat, but I still got the problem. As usual I'm sure it will turn out to be some silly small thing (and not a mysterious alignment issue with CBLAS). The strange thing is that the problem only arises when the matrices involved exceed a certain size. Rick On 4-Jun-08, at 2:08 PM, Kyle Sluder wrote: Take a look at NSInteger and CGFloat, and the 64-Bit Transition Guide for Cocoa: http://developer.apple.com/documentation/Cocoa/Conceptual/Cocoa64BitGuide/ConvertingExistingApp/chapter_4_section_3.html --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 [EMAIL PROTECTED]
Problem with cblas_sgemm in 64 bit build
I've been tesing a 64 bit build of an application that uses the BLAS function cblas_sgemm to multiply two matrices. The code works fine in 32 bit builds (building with Xcode 3.0 on Leopard 10.5.3) There is a strange problem that I think I have isolated to the output of the above function - when the matrix dimensions exceed a certain size, the output matrix (the product) contains rows that are zeroed out. I feel like it must be some aspect of my code that is not 64 bit clean, but I just can't track it down. The BLAS multiplication function is wrapped in a method of a matrix class I have implemented - the code is provided below. If anyone can spot any potential problems lurking in this code, I would be grateful. I have read the 64-bit transition guide and complied with all the recommendations as far as I can tell. I was wondering if it could be some kind of an alignment problem, but as the data are 4-byte floats (which don't change size under 64 bits) I don't really see how... Thanks - Rick // Here is the code: -(NLMatrix *)mTimes:(NLMatrix *)matrix2 { // Matrix multiply two matrices, return the result // Do some error checking if (numColumns != [matrix2 numRows]) { NSLog(@"Error: columns1 must equal rows2 for matrix multiplication"); } float *mat1Data = (float*)[self bytes]; float *mat2Data = (float*)[matrix2 bytes]; int numRows2 = [matrix2 numRows]; // This method returns int int numColumns2 = [matrix2 numColumns]; // This also returns int float *newData = (float*)malloc(numRows * numColumns2 * (int)sizeof(float)); float alpha = 1.0f; float beta = 0.0f; // NSLog(@"Multiplying a %dx%d matrix by a %dx%d matrix (result is %dx%d)", // numRows,numColumns,numRows2,numColumns2,numRows,numColumns2); // Use cblas_sgemm to compute product: C = alpha*A * B + beta*C cblas_sgemm (CblasColMajor, // Matrix is in column major order CblasNoTrans,// Don't transpose A CblasNoTrans,// Don't transpose B numRows, // Number of rows in A (and C) numColumns2, // Number of columns in B (and C) numColumns, // Number of columns in A (and rows in B) alpha, // Scalar factor multiplying A mat1Data,// Pointer to A numRows, // Length of leading dim of A (number of rows for col major) mat2Data,// Pointer to B numRows2, // Length of leading dim of B (number of rows for col major) beta,// Scalar factor multiplying C newData, // Pointer to C numRows // Length of leading dim of C (number of rows for col major) ); NLMatrix *newMatrix = [[NLMatrix alloc] initWithBytes:newData rows:numRows columns:numColumns2]; free(newData); return [newMatrix autorelease]; } ___ 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 [EMAIL PROTECTED]