Re: Issue with -[NSOutlineView autosaveExpandedItems] - SOLVED
On Jul 12, 2014, at 5:57 PM, Ken Thomases k...@codeweavers.com wrote: You could do it this way: __block void (^__unsafe_unretained innerFindItemForIdentifierInArray)(NSArray *); Thanks. I had gotten as far as thinking that I needed a second block variable for the recursive call, but the proper placement of __unsafe_unretained didn't come to me. This still has a problem. It doesn't stop when you intend it to. Any given -enumerate... call will stop if it directly finds the match, but an outer call won't. You could add if (returnItem) *stop = YES; after the recursive call. Or, you could pass the stop variable into the recursive call so that an inner call can set it. Thank you for catching that! I was so focused on getting the block syntax right that I completely overlooked the recursion issue. Here's the final method. I should mention that my datasource is a property list (hence my use of dictionaries). The root array does not have an identifier. That's why I start right out with -enumerateObjectsUsingBlock:. I chose to use blocks instead of recursive method calls partly to force myself to become more familiar with block syntax, and partly because I understand that blocks executing on the stack are likely to be faster. This method may have to enumerate the datasource many times, depending on how many of the outline rows are expanded. - (id)outlineView:(NSOutlineView *)outlineView itemForPersistentObject:(id)object { // Datasource method per NSOutlineViewDataSource formal protocol. Required if using autosaveExpandedItems. Called when application launches, once for each item in the autosaved array in the user defaults preferences file. AppKit calls this before -awakeFromNib, so the source list data source must be populated in the designated initializer. NSString *identifier = [NSKeyedUnarchiver unarchiveObjectWithData:object]; __block id returnItem = nil; __block void (^__unsafe_unretained innerFindItemForIdentifierInArray)(NSArray *); __block void (^findItemForIdentifierInArray)(NSArray *) = ^(NSArray *contents) { [contents enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { if ([[obj objectForKey:ID_KEY] isEqualToString:identifier]) { returnItem = obj; *stop = YES; } id subarray = [obj objectForKey:CONTENTS_KEY]; if (subarray) { innerFindItemForIdentifierInArray(subarray); // recursive if (returnItem) { *stop = YES; } } }]; }; innerFindItemForIdentifierInArray = findItemForIdentifierInArray; findItemForIdentifierInArray([self sourceListContents]); return returnItem; } -- Bill Cheeseman - b...@cheeseman.name ___ 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: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: KVC, binding multiple properties, top level object
On 12 Jul 2014, at 10:05 pm, Trygve Inda cocoa...@xericdesign.com wrote: ---someProperty (Custom NSObject) --propertyA (NSNumber) --propertyB (NSNumber) --propertyC (NSNumber) Properties A, B and C use a binding to connect them to a user interface item with something like: Bind to MyObject with key path someProperty.propertyA Just as a matter of interest, why do you decalre these subproperties as NSNumber types? Is there a reason you can't just make them the native scalar types they wrap (e.g. integer, float)? KVC/KVO automatically wraps scalar values with NSNumber or NSValue to pass them around through bindings, so you don't have to concern yourself with it. Usually, code is clearer if properties are declared as the native types. If you make them NSNumbers, how will you detect or prevent a value of the wrong type being passed? --Graham Would using NSInteger (instead of NSNumber) still work right when doing KVC in something like: -(void)encodeWithCoder:(NSCoder *)coder; { for (NSString* key in [self propertyKeys]) [coder encodeObject:[self valueForKey:key] forKey:key]; } What gets returned from [self valueForKey:key]? I guess the system wrapes the NSInteger in an NSNumber? ___ 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: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
-[NSOutlineView autosaveExpandedItems] bug?
I have encountered what I consider a bug, or at least a design error, in the NSOutlineView autosaveExpandedItems mechanism. Normally, when you expand or collapse an outline row, AppKit calls the NSOutlineViewDataSource method -outineView:persistentObjectForItem:, if it is implemented, to autosave an archive of the expanded or collapsed item. After you quit and relaunch the application, AppKit calls -outlineView:itemForPersistentObject: to read the archive and expand or collapse rows just as you left them when you quit. Here's the bug: When you expand or collapse an empty outline row, AppKit does not call -outineView:persistentObjectForItem:. As a result, after quit and relaunch the row is always in the collapsed state (the triangle points sideways instead of down), even if it was left in the expanded state at the previous quit. I suspect that Apple considers this to be correct behavior, since the NSOutlineViewItemDidExpandeNotification and NSOutlineViewItemDidCollapseNotification are correctly posted even when an empty row is expanded or collapsed. It therefore looks like Apple coded the autosave behavior deliberately. You might argue that this is proper behavior because it doesn't mean much to call an empty row expanded. But the Finder, for one example, honors the expanded state of empty rows across relaunches, and I find it useful so that I can monitor at a glance whether files have been added to particular folders behind my back (in my Public Folder's Drop Box, for example). I like to leave some empty folders expanded across relaunches. But the bug really bites when you expand an empty row and then add a child row to it. AppKit did not call -outineView:persistentObjectForItem: when you expanded the empty row, and it does not call it when you add a new child row, either. As a result, after quit and relaunch the row is collapsed, even though when you quit you left it expanded and non-empty. I can fix this with a hack. When I add a child row, my application checks whether the newly added row has any siblings and, if not, collapses and re-expands the row programmatically. Because the parent row now has a child, AppKit calls -outineView:persistentObjectForItem: and all is well. On my fast Mac Pro Late-2013, I don't see a flicker. I haven't tried it on a slower machine yet. A more dubious fix is to archive the expanded row in user defaults myself. I took a stab at coding that, and it wasn't hard, but I didn't carry it all the way through because I realized that I can't be sure I am capturing all the wrinkles of Apple's implementation. I consider this fix inappropriate for a released product because it depends on the implementation details of AppKit's autosaveExpandedItems mechanism, which is mostly hidden behind the scenes. Before I report this to Apple, does anybody have any other thoughts or workarounds? -- Bill Cheeseman - b...@cheeseman.name ___ 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: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Getting bound object
Hello, I have a collection view in which I have subclassed the collection view item. In the awake from nib method I want to get the represented object but it is returning nil How can I get the bound object ? ___ 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: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Getting bound object
On Jul 13, 2014, at 11:24 AM, Daniel Santos daniel.d...@gmail.com wrote: Hello, I have a collection view in which I have subclassed the collection view item. In the awake from nib method I want to get the represented object but it is returning nil How can I get the bound object ? You have to wait until after -awakeFromNib. Bindings aren't hooked up and propagated until the entire object graph has been awoken. One option is to override -loadView to call super and then do your magic. --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: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: KVC, binding multiple properties, top level object
On 12 Jul 2014, at 10:05 pm, Trygve Inda cocoa...@xericdesign.com wrote: ---someProperty (Custom NSObject) --propertyA (NSNumber) --propertyB (NSNumber) --propertyC (NSNumber) Properties A, B and C use a binding to connect them to a user interface item with something like: Bind to MyObject with key path someProperty.propertyA Just as a matter of interest, why do you decalre these subproperties as NSNumber types? Is there a reason you can't just make them the native scalar types they wrap (e.g. integer, float)? KVC/KVO automatically wraps scalar values with NSNumber or NSValue to pass them around through bindings, so you don't have to concern yourself with it. Usually, code is clearer if properties are declared as the native types. If you make them NSNumbers, how will you detect or prevent a value of the wrong type being passed? --Graham Is NSInteger treated the same way? This page does not mention it: https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/KeyVa lueCoding/Articles/DataTypes.html NSNumber just seem a bit more flexible since they can be added to dictionaries (such as in the userInfo of a Notification). T. ___ 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: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Getting bound object
On 13 Jul 2014, at 21:10, Kyle Sluder k...@ksluder.com wrote: On Jul 13, 2014, at 11:24 AM, Daniel Santos daniel.d...@gmail.com wrote: Hello, I have a collection view in which I have subclassed the collection view item. In the awake from nib method I want to get the represented object but it is returning nil How can I get the bound object ? You have to wait until after -awakeFromNib. Bindings aren't hooked up and propagated until the entire object graph has been awoken. One option is to override -loadView to call super and then do your magic. --Kyle Sluder I just tried that. But [self representedObject] returns nil when called in the subclassed NSCollectionViewItem. Any idea why ? ___ 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: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Getting bound object
On Jul 13, 2014, at 5:24 PM, Daniel Luis dos Santos daniel.d...@gmail.com wrote: On 13 Jul 2014, at 21:10, Kyle Sluder k...@ksluder.com wrote: On Jul 13, 2014, at 11:24 AM, Daniel Santos daniel.d...@gmail.com wrote: Hello, I have a collection view in which I have subclassed the collection view item. In the awake from nib method I want to get the represented object but it is returning nil How can I get the bound object ? You have to wait until after -awakeFromNib. Bindings aren't hooked up and propagated until the entire object graph has been awoken. One option is to override -loadView to call super and then do your magic. I just tried that. But [self representedObject] returns nil when called in the subclassed NSCollectionViewItem. Any idea why ? The collection view creates an item. Then it assigns that item the object it will represent. It can't do that until after the item has been created. That means after -awakeFromNib and after -loadView. The item's representedObject is not an inherent value that it can be expected to have at creation/load time. I don't know what you're trying to achieve. It may make sense to override the setter (-setRepresentedObject:) to have an opportunity to do something when the represented object is assigned to the item. Of course, call through to super. Regards, Ken ___ 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: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: KVC, binding multiple properties, top level object
On 14 Jul 2014, at 7:29 am, Trygve Inda cocoa...@xericdesign.com wrote: Is NSInteger treated the same way? This page does not mention it: NSInteger is a typedef for 'long', which size depends on the platform (32/64 bit), so valueForKey: will wrap it as a NSNumber using type 'long'. That's safe across archives that are used in both 32 and 64 bit ISAs, though with loss of precision if a 64-bit archive was dearchived on 32-bit (and this might become a permanent loss if the data is reachived and then opened in 64-bit). Scalar properties that explicitly declare 'long long' would be always 64-bit. I doubt if this is an issue in practice. NSNumber just seem a bit more flexible since they can be added to dictionaries (such as in the userInfo of a Notification). Since - valueForKey: always returns an object, they too can be added to dictionaries. I guess it's as broad as it's long, though my view would be that it's generally a better idea to take advantage of a framework feature where it exists (in this case, the auto wrapping and unwrapping of scalars) than roll your own solution which won't be as thoroughly debugged, take into account any corner cases, and so on. In this case it's also much less type safe. The auto-wrapping generally preserves type, or at least preserves precision (NSNumbers don't actually guarantee that a value's type won't change, e.g. a float that can be expressed as an integer will probably end up as an integer, but the point is there's no loss of precision). --Graham ___ 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: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: KVC, binding multiple properties, top level object
On 14 Jul 2014, at 7:29 am, Trygve Inda cocoa...@xericdesign.com wrote: Is NSInteger treated the same way? This page does not mention it: NSInteger is a typedef for 'long', which size depends on the platform (32/64 bit), so valueForKey: will wrap it as a NSNumber using type 'long'. That's safe across archives that are used in both 32 and 64 bit ISAs, though with loss of precision if a 64-bit archive was dearchived on 32-bit (and this might become a permanent loss if the data is reachived and then opened in 64-bit). Scalar properties that explicitly declare 'long long' would be always 64-bit. I doubt if this is an issue in practice. So what is the purpose of valueForInteger ? ___ 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: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: KVC, binding multiple properties, top level object
On 14 Jul 2014, at 7:29 am, Trygve Inda cocoa...@xericdesign.com wrote: Is NSInteger treated the same way? This page does not mention it: NSInteger is a typedef for 'long', which size depends on the platform (32/64 bit), so valueForKey: will wrap it as a NSNumber using type 'long'. That's safe across archives that are used in both 32 and 64 bit ISAs, though with loss of precision if a 64-bit archive was dearchived on 32-bit (and this might become a permanent loss if the data is reachived and then opened in 64-bit). Scalar properties that explicitly declare 'long long' would be always 64-bit. I doubt if this is an issue in practice. So what is the purpose of the NSInteger access within NSNumber eg integerValue and setIntegerValue ? Please disregard my last message - it got sent before I could stop it. :-) ___ 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: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com