Quindi sto usando i blocchi ricorsivi. Capisco che affinché un blocco sia ricorsivo, deve essere preceduto dalla parola chiave __block e deve essere copiato in modo che possa essere messo sullo heap. Tuttavia, quando lo faccio, si presenta come una perdita in Strumenti. Qualcuno sa perché o come posso aggirarlo?Blocchi ricorsivi in Objective-C che perdono in ARC
Si prega di notare nel codice qui sotto ho riferimenti a molti altri blocchi, ma nessuno di essi è ricorsivo.
__block NSDecimalNumber *(^ProcessElementStack)(LinkedList *, NSString *) = [^NSDecimalNumber *(LinkedList *cformula, NSString *function){
LinkedList *list = [[LinkedList alloc] init];
NSDictionary *dict;
FormulaType type;
while (cformula.count > 0) {
dict = cformula.pop;
type = [[dict objectForKey:@"type"] intValue];
if (type == formulaOperandOpenParen || type == formulaListOperand || type == formulaOpenParen) [list add:ProcessElementStack(cformula, [dict objectForKey:@"name"])];
else if (type == formulaField || type == formulaConstant) [list add:NumberForDict(dict)];
else if (type == formulaOperand) [list add:[dict objectForKey:@"name"]];
else if (type == formulaCloseParen) {
if (function){
if ([function isEqualToString:@"AVG("]) return Average(list);
if ([function isEqualToString:@"MIN("]) return Minimum(list);
if ([function isEqualToString:@"MAX("]) return Maximum(list);
if ([function isEqualToString:@"SQRT("]) return SquareRoot(list);
if ([function isEqualToString:@"ABS("]) return EvaluateStack(list).absoluteValue;
return EvaluateStack(list);
} else break;
}
}
return EvaluateStack(list);
} copy];
NSDecimalNumber *number = ProcessElementStack([formula copy], nil);
UPDATE Così nella mia ricerca ho scoperto che il problema a quanto pare non hanno a che fare con i riferimenti alle altre blocchi questo blocco utilizza. Se faccio qualcosa di semplice come questo, non perde:
__block void (^LeakingBlock)(int) = [^(int i){
i++;
if (i < 100) LeakingBlock(i);
} copy];
LeakingBlock(1);
Tuttavia, se posso aggiungere un altro blocco in questo, lo fa perdita:
void (^Log)(int) = ^(int i){
NSLog(@"log sub %i", i);
};
__block void (^LeakingBlock)(int) = [^(int i){
Log(i);
i++;
if (i < 100) LeakingBlock(i);
} copy];
LeakingBlock(1);
Ho provato con il __block parola chiave per Log() e anche provato a copiarlo, ma perde ancora. Qualche idea?
UPDATE 2 Ho trovato un modo per prevenire la perdita, ma è un po 'oneroso. Se converto il blocco passato in un ID debole e quindi restituisco l'ID debole in un tipo di blocco, posso impedire la perdita.
void (^Log)(int) = ^(int i){
NSLog(@"log sub %i", i);
};
__weak id WeakLogID = Log;
__block void (^LeakingBlock)(int) = [^(int i){
void (^WeakLog)(int) = WeakLogID;
WeakLog(i);
if (i < 100) LeakingBlock(++i);
} copy];
LeakingBlock(1);
Sicuramente c'è un modo migliore?
Grazie per aver condiviso la tua ricerca, non ho sentito di dover copiare anche il blocco. Tuttavia, sembra che un LLVM più recente emetta un avviso alla chiamata ricorsiva "catturare LeakingBlock" in questo blocco è probabile che porti a un ciclo di conservazione ".L'unico modo che ho trovato per placare il compilatore è quello di usare un ptr debole separato per il blocco in qualche modo simile alla tua risposta qui sotto, anche se è abbastanza maneggevole che sono tentato di sovrascrivere localmente l'avviso. Sarei interessato a vedere la tua opinione quando proverai l'ultimo compilatore. –
@smallduck Originariamente, ho usato 'copia' perché fa sì che il blocco venga copiato nell'heap dalla pila. Per un po 'ha funzionato bene e ho anche ricevuto l'errore "ricorsivo" del compilatore. Ho rimosso 'copia' dal mio codice (come riportato nella mia risposta) e ha funzionato (mentre prima avrei avuto' EXC_BAD_ACCESS'. Sto supponendo che Apple abbia modificato la parola chiave '__block' per creare blocchi sull'heap piuttosto che su lo stack ... ma è solo una supposizione: –
@smallduck Sinceramente, ho rinunciato a usare i blocchi per la ricorsione Sì, può essere fatto ma è un po 'pesante e ci sono troppe insidie. È troppo facile finire con mantiene i cicli (che possono essere davvero pessimi con la ricorsione) e diventa difficile da leggere.Quindi di solito mi limito a metodi/funzioni per fare la ricorsione .. –