recursive blocks?

Discussion in 'Mac Programming' started by MrFusion, Aug 12, 2010.

  1. MrFusion macrumors 6502a

    Joined:
    Jun 8, 2005
    Location:
    West-Europe
    #1
    Is it possible to have a recursive block? I tried the code below, but it gives a "block is nil" message.

    Code:
    	NSArray *arr = [NSArray arrayWithObjects:@"test",[NSArray arrayWithObject:@"test"],nil];
    	
    	__block NSMutableArray *output = [NSMutableArray arrayWithCapacity:10];
    	
    	void (^recusive_loop)(id, NSUInteger, BOOL *) = ^(id obj, NSUInteger idx, BOOL *stop) {
    		if ([[obj class] isSubclassOfClass:[NSArray class]])
    			[obj enumerateObjectsUsingBlock:recusive_loop];
    		else
    			[output addObject:obj];
    	};
    	
    	[arr enumerateObjectsUsingBlock:recusive_loop];
    
     
  2. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #2
    At the time of definition the block is nil; it is being created, then assigned.

    The other issue is going to be that blocks form a closure, so it's going to enclose the values at the time of definition. I'm imagining ways around this, such as a block-returning function. While it may work, I'm not totally sure why you need to do this.

    -Lee
     
  3. kpua macrumors 6502

    Joined:
    Jul 25, 2006
    #3
    This should work for you:

    Code:
    	NSArray *arr = [NSArray arrayWithObjects:@"test",[NSArray arrayWithObject:@"test"],nil];
    	
    	__block NSMutableArray *output = [NSMutableArray arrayWithCapacity:10];
    	
    	__block void (^recusive_loop)(id, NSUInteger, BOOL *);
    	recursive_loop = ^(id obj, NSUInteger idx, BOOL *stop) {
    		if ([[obj class] isSubclassOfClass:[NSArray class]])
    			[obj enumerateObjectsUsingBlock:recusive_loop];
    		else
    			[output addObject:obj];
    	};
    	
    	[arr enumerateObjectsUsingBlock:recusive_loop];
     
  4. MrFusion thread starter macrumors 6502a

    Joined:
    Jun 8, 2005
    Location:
    West-Europe
    #4
    That makes sense.

    Two examples I have in mind are stepping through a file directory and through a nodetree (NSTreeController) whereby the processing of each file or datanode can take a significant amount of resources. Some files/nodes might take longer to process than others.

    Code:
    NSArray of urls/treenodes specified by user
    go through the items in the array
       process each item
       if item has children, 
          create NSArray of children
          repeat loop for each child
    
    I have this code which works fine and which does not block my program as before (spinning beach ball). I just figured, why not make it recursive.

    Code:
    void (^import_loop)(id, NSUInteger, BOOL *) = ^(id url, NSUInteger idx, BOOL *stop)
    { 
     //do stuff
    };
    [urls enumerateObjectsWithOptions:NSEnumerationConcurrent 
    	  		   usingBlock:import_loop];
    
    Thanks for the reply.
     
  5. Catfish_Man macrumors 68030

    Catfish_Man

    Joined:
    Sep 13, 2001
    Location:
    Portland, OR
    #5
    The trick to recursive blocks is that they have to be declared __block, and then assigned, like so:

    Code:
    __block dispatch_block_t recursiveBlock;
    recursiveBlock = ^{
        recursiveBlock();
    };
    
     
  6. MrFusion thread starter macrumors 6502a

    Joined:
    Jun 8, 2005
    Location:
    West-Europe
    #6
    Thanks kpua and Catfish_Man. This approach works.
     

Share This Page