2013-03-20 8 views
7

Sono sorpreso di trovare il seguente comportamento ...I blocchi mantengono il ciclo dalla convenzione di denominazione?

@interface Foo : NSObject 

- (void)addBar:(id)aBar withCompletion:(void(^)(void))completion; 

@end 

@interface AwesomeClass : NSObject 

@property (strong, nonatomic) Foo *foo; 

- (void)doSomethingWithBar:(id)bar; 

@end 

@implementation AwesomeClass 

- (void)doSomethingWithBar:(id)bar 
{ 
    [self.foo addBar:bar withCompletion:^{ 
     NSLog(@"%@", self.foo); 
    }]; 
} 

In Xcode 4.6.1 Ho ricevuto un avviso nella realizzazione di -doSomethingWithBar: che "Capturing 'sé' fortemente in questo blocco rischia di portare ad una mantenere il ciclo. "

Tuttavia, se il refactoring nome del metodo -addBar:withCompletion:--setupBar:withCompletion: questo avvertimento va via. Sembra che la mia sorpresa da questo illustra che ho una lacuna nelle mie conoscenze riguardanti le convenzioni di denominazione Objective-C!

+1

Prova a ricompilare. L'avvertimento non sta "andando via", tanto quanto Xcode è stato idiota e scarica gli avvertimenti LLVM ha generato l'ultima volta – CodaFi

risposta

19

Il codice

[self.foo someMethod:bar withCompletion:^{ 
    NSLog(@"%@", self.foo); 
}]; 

non significa generalmente creare un ciclo conservare. Se someMethod:withCompletion: chiama solo il blocco e ritorna, non vi è alcun ciclo di conservazione. (-[NSArray enumerateObjectsUsingBlock:] è un esempio.)

Solo se someMethod:withCompletion: "ricorda" il blocco da eseguire in un secondo momento, è possibile un ciclo di conservazione. Quindi clang usa un euristico per decidere se è un metodo "setter-like" che memorizza il blocco in una proprietà di Foo da eseguire successivamente.

-set<Key> e -add<Key> sono modelli accessor a valore-chiave di codifica per impostare una proprietà o aggiungere un valore a un (a-molti) rapporto, e questo è esattamente ciò Clang controlli per.

questo può essere visto nella Clang source code:

/// Check for a keyword selector that starts with the word 'add' or 
/// 'set'. 
static bool isSetterLikeSelector(Selector sel) { 
    if (sel.isUnarySelector()) return false; 

    StringRef str = sel.getNameForSlot(0); 
    while (!str.empty() && str.front() == '_') str = str.substr(1); 
    if (str.startswith("set")) 
    str = str.substr(3); 
    else if (str.startswith("add")) { 
    // Specially whitelist 'addOperationWithBlock:'. 
    if (sel.getNumArgs() == 1 && str.startswith("addOperationWithBlock")) 
     return false; 
    str = str.substr(3); 
    } 
    else 
    return false; 

    if (str.empty()) return true; 
    return !islower(str.front()); 
} 

che si chiama qui:

/// Check a message send to see if it's likely to cause a retain cycle. 
void Sema::checkRetainCycles(ObjCMessageExpr *msg) { 
    // Only check instance methods whose selector looks like a setter. 
    if (!msg->isInstanceMessage() || !isSetterLikeSelector(msg->getSelector())) 
    return; 

    /* 
    * rest omitted 
    */ 

} 

Il tuo metodo setupBar è non trattata come metodo di "setter-like", perché "set" non è seguito da una lettera maiuscola.

Problemi correlati