Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

MrFusion

macrumors 6502a
Original poster
Jun 8, 2005
613
0
West-Europe
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];
 
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
 
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];
 
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.

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.
 
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();
};
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.