Hoy estaba experimentando con bloques de Objective-C, así que pensé que sería inteligente y añadir a NSArray unos métodos de recolección de estilo funcional que he visto en otros idiomas:El uso de Objective-C Bloques
@interface NSArray (FunWithBlocks)
- (NSArray *)collect:(id (^)(id obj))block;
- (NSArray *)select:(BOOL (^)(id obj))block;
- (NSArray *)flattenedArray;
@end
El método collect: toma un bloque que se llama para cada elemento de la matriz y se espera que devuelva los resultados de alguna operación utilizando ese elemento. El resultado es la recopilación de todos esos resultados. (Si el bloque devuelve nulo, no se agrega nada al conjunto de resultados.)
El método select: devolverá una nueva matriz con solo los elementos del original que, cuando se pasa como argumento al bloque, el bloque devuelto SÍ.
Y, por último, el método flattenedArray itera sobre los elementos de la matriz. Si un elemento es una matriz, recursivamente llama a flattenedArray y agrega los resultados al conjunto de resultados. Si el elemento no es una matriz, agrega el elemento al conjunto de resultados. El conjunto de resultados se devuelve cuando todo está terminado.
Así que ahora que tenía algo de infraestructura, necesitaba un caso de prueba. Decidí encontrar todos los archivos del paquete en los directorios de la aplicación del sistema. Esto es lo que se me ocurrió:
NSArray *packagePaths = [[[NSSearchPathForDirectoriesInDomains(NSAllApplicationsDirectory, NSAllDomainsMask, YES) collect:^(id path) { return (id)[[[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:nil] collect:^(id file) { return (id)[path stringByAppendingPathComponent:file]; }]; }] flattenedArray] select:^(id fullPath) { return [[NSWorkspace sharedWorkspace] isFilePackageAtPath:fullPath]; }];
Sí, eso es una línea y es horrible. Probé algunos enfoques para agregar nuevas líneas y sangrías para tratar de limpiarlo, pero todavía parece que el algoritmo real se pierde en todo el ruido. Sin embargo, no sé si solo se trata de una cuestión de sintaxis o de mi relativa experiencia en relación con el uso de un estilo funcional.
Para la comparación, me decidieron a hacerlo "de la manera antigua" y sólo tiene que utilizar bucles:
NSMutableArray *packagePaths = [NSMutableArray new];
for (NSString *searchPath in NSSearchPathForDirectoriesInDomains(NSAllApplicationsDirectory, NSAllDomainsMask, YES)) {
for (NSString *file in [[NSFileManager defaultManager] contentsOfDirectoryAtPath:searchPath error:nil]) {
NSString *packagePath = [searchPath stringByAppendingPathComponent:file];
if ([[NSWorkspace sharedWorkspace] isFilePackageAtPath:packagePath]) {
[packagePaths addObject:packagePath];
}
}
}
OMI esta versión fue más fácil de escribir y es más fácil de leer para arrancar.
Supongo que es posible que este sea de alguna manera un mal ejemplo, pero parece una forma legítima de usar bloques para mí. (¿Estoy equivocado?) ¿Me falta algo sobre cómo escribir o estructurar el código Objective-C con bloques que limpiarían esto y lo dejarían más claro que (o incluso tan claro como) la versión en bucle?
buena solución, aunque no soy un gran fan de la redefinición de 'paths' varias veces. Probablemente terminaré nombrando varios valores basados en su contenido, y terminaré con uno llamado 'paths'. Solo mis dos centavos. –
La animación de UIView usa 2 bloques. –
Dijo patrón no canon. Esos métodos que toman todos los bloques tienen todos los bloques como los parámetros finales. Además, esas API aparecieron en iOS 4, que fue mucho después de esta publicación. – logancautrell