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

Reply via email to