2014-03-19 10 views
6

Wenn ich einen Block eine Objective C-Instanz erstellen, die auf die Instanz verweisen muss ich so durch einen schwachen Zeiger häufig tun, die die Instanz nicht halten lebendig und einen Zyklus beibehalten produzieren, wie folgt aus:Idiom, um "self" in Objective C-Blöcken zu verstecken?

__weak MyType *const weakSelf = self; 
void (^aBlock)() = ^(){ 
    // Do things with weakSelf instead of self. 
} 

Ich hätte gerne ein Idiom, das mich daran hindert, das starke Selbst im Block zu nutzen. Im Idealfall würde ich bei Verwendung des Idioms einen Kompilierungsfehler erhalten, wenn ich versuche, self im Block anstelle von weakSelf zu verwenden. Ein Laufzeitfehler wäre auch okay.

+3

können Sie eine Warnung dafür bekommen .. würde das helfen? –

+2

Neueste Versionen von Xcode + ARC erkennen starke Referenzzyklen in Blöcken und warnen Sie. –

+0

Die Warnung ist hilfreich, danke. Ich habe eine Lösung, die ich veröffentlichen werde. Es ist nicht perfekt, aber es könnte eine bessere Lösung hervorbringen. – Benjohn

Antwort

1

Ich habe eine Lösung dafür bekam, dass Ich mag nicht besonders, aber es könnte eine bessere Antwort provozieren. Ich werde das in der Hoffnung auf eine bessere Lösung unbeantwortet lassen.

Hier ist eine Möglichkeit, es zu tun:

// Here's a method definition… 
-(void) aMethod 
{ 
    // Want to create a block in which its impossible to refer to strong "self". 
    // Begin a new scope to do this in. 
    { 
    // Within this scope, cover the existing "self" with a weak variant. 
    __weak STWeatherTableViewController const *weakSelf = self; 
    __weak STWeatherTableViewController const *self = weakSelf; 

    // Sadly it's _not_ possible to simply do: 
    // __weak STWeatherTableViewController const *self = self; 
    // … it gives a warning about initialisation of a variable form its own 
    // uninitialised value, which makes sense, though you might hope the 
    // compiler would work out what's going on. 

    // Make a block that captures the covered self and does something with it. 
    void (^exampleBlock)() = ^(){ [self lineHeight]; }; 
    exampleBlock(); 
    } 

    // Now, back in the scope of the original method, "self" is non weak 
    // again. 
    [self doSomething]; 
} 

Ich denke, wenn Sie wirklich viel über diese gepflegt, könnten Sie ein Makro verwenden. Es wäre zumindest abstrakt die Idee und machen nutzt einfach und Hinweise im Code zu finden:

#define WEAKEN_SELF(classType) \ 
__weak classType const *weakSelf = self; \ 
__weak classType const *self = weakSelf 

Oder auch:

#define WEAKEN_SELF(classType) \ 
__weak classType const *weakSelfTemporary##__LINE__ = self; __weak classType const *self = weakSelfTemporary##__LINE__; 

Welche Sie es wie folgt verwenden würde:

-(void) testMethod 
{ 
    // You still need that scope or you cover the original "self". 
    { 
    WEAKEN_SELF(STWeatherTableViewController) 
    void (^exampleBlock)() = ^(){ [self someMethodOrOther]; }; 
    exampleBlock(); 
    } 
} 

Ich bin nicht überzeugt, aber es lohnt sich die Mühe. Die Warnungen des Compilers sind wahrscheinlich gut genug und sie können vermutlich in Fehler umgewandelt werden?

+0

Interessante Lösung :) –

Verwandte Themen