Método recursivo con bloque y detener arguments

He escrito una categoría en UIView que me permite recorrer la jerarquía de vistas:

UIView + Capture.h

 typedef void(^MSViewInspectionBlock)(UIView *view, BOOL *stop); @interface UIView (Capture) - (void)inspectViewHeirarchy:(MSViewInspectionBlock)block; @end 

UIView + Capture.m

 @implementation UIView (Capture) - (void)inspectViewHeirarchy:(MSViewInspectionBlock)block { BOOL stop = NO; [self inspectViewHeirarchy:block stop:stop]; } #pragma - Private - (void)inspectViewHeirarchy:(MSViewInspectionBlock)block stop:(BOOL)stop { if (!block || stop) { return; } block(self, &stop); for (UIView *view in self.subviews) { [view inspectViewHeirarchy:block stop:stop]; if (stop) { break; } } } @end 

Que puedes usar así:

 [[[UIApplication shanetworkingApplication] keyWindow] inspectViewHeirarchy:^(UIView *view, BOOL *stop) { if ([view isMemberOfClass:[UIScrollView class]]) { NSLog(@"Found scroll view!"); *stop = YES; } }]; 

Todo funciona bien, excepto que la configuration se stop en YES . Esto parece no tener absolutamente ningún efecto. Lo ideal sería que me detuviera la recursion, así que cuando encontré la vista en la que quiero tomar alguna acción, no tengo que seguir recorriendo el rest de la jerarquía de la vista.

Soy bastante denso cuando se trata de usar bloques, así que puede ser algo completamente obvio. Cualquier ayuda será apreciada.

Supongo que desea regresar completamente desde el nivel superior inspectViewHierarchy cuando el usuario establece stop en YES .

(Incidentalmente, escribiste "jerarquía" mal y debes usar un prefijo en los methods que agregas a las classs estándar).

 @implementation UIView (Capture) - (void)micpringle_visitSubviewsRecursivelyWithBlock:(MSViewInspectionBlock)block { BOOL stop = NO; [self inspectViewHierarchy:block stop:&stop]; } #pragma - Private - (void)micpringle_visitSubviewsRecursivelyWithBlock:(MSViewInspectionBlock)block stop:(BOOL *)stop { block(self, stop); if (*stop) return; for (UIView *view in self.subviews) { [view micpringle_visitSubviewsRecursivelyWithBlock:block stop:stop]; if (*stop) break; } } @end 

La forma en que está utilizando un bloque es exactamente lo mismo que usar una function C. Entonces, no hay nada especial que realmente necesites saber sobre los bloques. Su código debería funcionar, pero tenga en count la diferencia entre pasar la stop como un BOOL * a su bloque y crear un nuevo local cuando vuelva a ingresar.

Parece que está esperando llamadas hacia abajo para inspectViewHierarchy:stop: para afectar la variable de stop externa. Eso no sucederá a less que lo pases como reference. Entonces, creo que lo que quieres es:

 - (void)inspectViewHeirarchy:(MSViewInspectionBlock)block stop:(BOOL *)stop 

… y otros cambios apropiados.

 - (BOOL) inspectViewHeirarchy:(MSViewInspectionBlock)block { BOOL stop = NO; block(self, &stop); if (stop) return YES; for (UIView *view in self.subviews) { if ([view inspectViewHeirarchy:block]) return YES; } return NO; } 

¿No querrías comprobar el estado de 'detener' directamente después de invocar el bloque? No ayuda invocarla después de llamar a inspectViewHierarchy: stop: porque está pasando una copy de 'stop' a ese método en lugar de la reference.

Prueba esto:

 - (void)inspectViewHeirarchy:(MSViewInspectionBlock)block { __block BOOL stop = NO; [self inspectViewHeirarchy:block stop:stop]; } 

Los bloques, por naturaleza, copyn las variables y el context en el que se declaran.

Aunque está pasando el boolean como reference, es posible que esté usando una copy del context y no la verdadera parada.

Esto es solo una conjetura salvaje pero, dentro de inspectViewHierarchy: stop: haz algo como:

 - (void)inspectViewHeirarchy:(MSViewInspectionBlock)block stop:(BOOL)stop { if (!block || stop) { return; } // Add these changes __block BOOL blockStop = stop; block(self, &blockStop); for (UIView *view in self.subviews) { [view inspectViewHeirarchy:block stop:stop]; if (stop) { break; } } } 

Esto puede ser muy importante y no estoy 100% seguro de que funcione sin tener su proyecto, pero vale la pena.

Además, refactorice su método para que "heirarchy" en realidad se escriba "jerarquía":] Es bueno para la reutilización y para mantener una buena base de código;)