¿Se necesita la palabra clave __block para escribir en bucle en el objetivo C cuando se muta una matriz o diccionario?
__block NSMutableArray *xxxx = [NSMutableArray new]; // is __block needed?
for (obj in objs) {
[xxx addObject];
}
3 respuestas
No, no es. La palabra clave __block
solo es necesaria cuando se cumplen varias condiciones:
- Hay un "bloque" de Objective-C: un segmento de código capturado como un objeto, y
- Hay una variable declarada fuera del bloque, y
- El valor de la variable se cambia dentro del bloque.
Esto podría ser más claro por contraejemplo. ¿Dónde no necesita la palabra clave __block
?
No lo necesita cuando su bucle es un bucle C simple, incluidos bucles simples for
y bucles que usan NSFastEnumeration:
NSInteger sum = 0;
for (NSInteger i = 0; i < 10; i++) {
sum += i; // okay! this is a plain C for loop
}
NSArray *numbers = @[@1, @2, @3];
for (NSNumber *i in numbers) {
sum += [i integerValue]; // okay! this is an NSFastEnumeration object loop
}
Cuando tiene un bloque Objective-C real, no lo necesita si el cuerpo del bloque realmente no muta el valor de la variable. Este suele ser el caso si su bloque solo envía mensajes Objective-C a un objeto:
NSMutableArray *evenNumbers = [NSMutableArray array];
NSArray *numbers = @[@1, @2, @3];
[numbers enumerateObjectsUsingBlock:^(NSNumber * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if ([obj integerValue] % 2 == 0) {
[evenNumbers addObject:obj]; // okay! this is an ObjC message send, which does not mutate the pointer value of `evenNumbers`
}
}];
El único caso que necesita es cuando su bloque intenta mutar el valor de una variable directamente.
__block NSString *match = nil;
__block NSUInteger matchIndex = NSNotFound;
NSArray *candidates = @[@"foo", @"bar"];
[candidates enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if ([obj isEqual:@"foo"]) {
// these must be __block, because we are mutating their values in this ObjC block
match = obj;
matchIndex = idx;
*stop = YES;
}
}];
No. __block
es necesario si el valor de la variable se cambia dentro del bloque, por ejemplo.
__block NSUInteger sum = 0;
[objs enumerateObjectsUsingBlock:
^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
sum += obj.number; // just imaginary
}];
En su caso, el valor de la variable es puntero y no se modifica.
No, en el fragmento de código que ha publicado no necesita el modificador __block
.
Nuevas preguntas
objective-c
Esta etiqueta debe usarse solo en preguntas sobre las características de Objective-C o que dependen del código en el lenguaje. Las etiquetas [cocoa] y [cocoa-touch] deben usarse para preguntar sobre los marcos o clases de Apple. Use las etiquetas relacionadas [ios], [macos], [apple-watch] y [tvos] para problemas específicos de esas plataformas.