[Self methodName] aus einem Block heraus aufrufen?

73

Ich bin gerade auf Blöcke gestoßen und ich denke, sie sind genau das, wonach ich suche, abgesehen von einer Sache: Ist es möglich, eine Methode [self methodName] aus einem Block heraus aufzurufen?

Das versuche ich zu tun:

-(void)someFunction{
    Fader* fader = [[Fader alloc]init];

    void (^tempFunction)(void) = ^ {
        [self changeWindow:game]; 
        //changeWindow function is located in superclass
    };

    [fader setFunction:tempFunction];
}

Ich habe seit ein paar Tagen gesucht und kann keine Beweise dafür finden, dass dies möglich ist.

Ist das überhaupt möglich oder versuche ich, Blöcke für etwas zu verwenden, für das sie nicht bestimmt sind?

Der Grund, warum ich Blöcke verwende, ist, dass ich eine Fader-Klasse erstellt habe und einen Block speichern möchte, damit er ausgeführt wird, wenn er ausgeblendet ist.

Vielen Dank

EDIT: Okay, ich habe den Vorschlag hinzugefügt, aber ich erhalte immer noch einen EXC_BAD_ACCESS-Fehler ...

-(void)someFunction{
    Fader* fader = [[Fader alloc]init];

    __block MyScreen* me = self;

    void (^tempFunction)(void) = ^ {
        [me changeWindow:game]; 
        //changeWindow function is located in superclass
    };

    [fader setFunction:tempFunction];
    [fader release];
}

Vielleicht darf ich dem Fader nicht die Funktion geben ...?

Marty
quelle
Die akzeptierte Antwort ist veraltet . Bitte akzeptieren Sie meine Antwort , um Leute nicht mit falscher Syntax zu verwechseln.
Skywinder

Antworten:

142

Ja, das kannst du machen.

Beachten Sie jedoch, dass der Block beibehalten wird self. Wenn Sie diesen Block in einem Ivar speichern, können Sie leicht einen Aufbewahrungszyklus erstellen, was bedeutet, dass keiner von beiden jemals freigegeben wird.

Um dies zu umgehen, können Sie Folgendes tun:

- (void) someMethodWithAParameter:(id)aParameter {

  __block MySelfType *blocksafeSelf = self;
  void (^tempFunction)(void) = ^ {
      [blocksafeSelf changeWindow:game];
  };

  [self doSomethingWithBlock:tempFunction];

}

Das __blockSchlüsselwort bedeutet (unter anderem), dass das referenzierte Objekt nicht beibehalten wird.

Dave DeLong
quelle
4
@Marty Stellen Sie sicher, dass die functionEigenschaft Ihres Schaltflächenobjekts eine copyEigenschaft und keine retainEigenschaft ist.
Dave DeLong
37
Beachten Sie, dass Sie auf diese Weise die Möglichkeit einführen self, ein baumelnder Zeiger zu werden und eine RTE zu verursachen, wenn der Block aufgerufen wird, nachdem d aufgerufen selfwurde dealloc. Vor ARC konnten Sie die MAZeroingWeakRef-Bibliothek von Mike Ash verwenden, um einen sicheren Verweis auf selfden Block zu erstellen . Nach ARC können Sie unter iOS 5.0 und höher das zusätzliche Schlüsselwort verwenden __weak, um Ihre Referenz auf sich selbst zu einer schwachen Nullreferenz zu machen.
Prairiedogg
2
"Das Schlüsselwort __block bedeutet (unter anderem), dass das referenzierte Objekt nicht beibehalten wird." Hat sich dies mit dem ARC geändert? "Die Inferenzregeln gelten gleichermaßen für __block-Variablen, was eine Verschiebung der Semantik gegenüber Nicht-ARC darstellt, bei der __block-Variablen während der Erfassung nicht implizit beibehalten wurden. "
Sergey Kalinichenko
1
@MobileMon Ja, denn das self.someProperty = ...ist das Gleiche wie [self setSomeProperty:...]. Sie erfassen immer noch selfim Block, haben also immer noch einen starken Referenzzyklus.
Dave DeLong
1
@ JayQ. es hängt davon ab, ob. Wenn Sie sehen, dass die Zuordnung aufgehoben wird, sind Sie in Ordnung. In meiner Antwort würde es einen Aufbewahrungszyklus geben, da "self" stark auf den Block verweisen würde, der Block jedoch stark auf self verweisen würde. Das ist ein Aufbewahrungszyklus, und es würde bedeuten, dass weder der Block noch das "Selbst" jemals freigegeben würden (weil beide wollen, dass sie am Leben bleiben). Wenn Sie sehen, dass "Selbst" freigegeben wird, haben Sie keinen Aufbewahrungszyklus.
Dave DeLong
25

Die akzeptierte Antwort ist veraltet . Die Verwendung __blockin diesem Fall kann zu Fehlern führen!

Um dieses Problem zu vermeiden, empfiehlt es sich, einen schwachen Verweis selfwie folgt zu erfassen :

- (void)configureBlock {
    XYZBlockKeeper * __weak weakSelf = self;
    self.block = ^{
        [weakSelf doSomething];   // capture the weak reference
                                  // to avoid the reference cycle
    }
}

Weitere Informationen finden Sie in der Apple-Dokumentation - Vermeiden Sie starke Referenzzyklen bei der Selbstaufnahme .

Skywinder
quelle
2
"Die Verwendung von __block kann in diesem Fall zu Fehlern führen!" - Bitte teilen Sie uns mit, welche Art von Fehlern.
Cristik
1
Was ist, wenn ich etwas Ähnliches wie "[self doStuff]" INNERHALB der Funktion "doSomething" habe? Es kann einen Haltezyklus verursachen? Oder nicht?
Superpuccio
@Cristik Zyklus beibehalten. da __blockgibt dir Zugriff innerhalb des Blocks, macht ihn aber nicht schwach.
Skywinder
@ Superpuccio nicht. die Methode als solche nicht. nur Objekte, die wir im Block
sotre
3
__block CURRENTViewController *blocksafeSelf = self;

[homeHelper setRestAsCheckIn:strRestId :^(NSObject *temp) {
    [blocksafeSelf YOURMETHOD:params];
}];
Ketan Patel
quelle
Dies wird automatisch als "niedrige Qualität" gekennzeichnet. Können Sie Text hinzufügen, um den Code zu erläutern und wie er die Frage des OP beantwortet?
Gung - Reinstate Monica
1

Ist es möglich, eine Methode [self methodName] innerhalb eines Blocks aufzurufen?

Ja, warum nicht. Wenn tempFunctiones sich um eine Instanzmethode handelt, können Sie dies tun. Die aufgerufene Methode sollte zugänglich sein, ist die einzige Einschränkung.

Mahesh
quelle
tempFunctionist keine Instanzmethode - es ist ein Block.
Ich denke, Mahesh meinte "wenn Sie tempFunctionsich in einer Instanzmethode befinden ..."
bbum
@bbum True; das macht mehr Sinn.
0

Betrachten Sie dies (was ich für die beste Vorgehensweise halte)

@implementaion ViewController

- (void) viewDidLoad {
  __weak typeof(self) wself = self;
  [xxx doSomethingUsingBlock: ^{
    __strong typeof(wself) self = wself;
    [self anotherMessage];
  }];
}

@end

Darüber hinaus können Sie Wrapper-Makros definieren.

#define MakeWeakSelf __weak typeof(self) wself = self
#define MakeStrongSelf __strong typeof(wself) self = wself
yuansi zhu
quelle
-1

Ich frage mich, ob Sie [Fader setFunction: tempFunction]; dann ist synchron oder asynchron. Blöcke werden in MRR auf stack.so verschoben. Wenn Sie sie nicht beibehalten, wird sie abgesprungen.

-(void)someFunction{
    Fader* fader = [[Fader alloc]init];

    void (^tempFunction)(void) = ^ {
        [self changeWindow:game]; 
        //changeWindow function is located in superclass
    };

    [fader setFunction:tempFunction];
    //if the tempFunction execute there will be right.
}//there the tempFunction pop off
 //....some thing go on
 //execute the tempFunction will go wrong.
user3073403
quelle
Das Aufrufen von 'self' innerhalb des Blocks behält es bei. Verwenden Sie __weak oder __block und erstellen Sie einen schwachen Verweis auf sich selbst, bevor Sie ihn in einem Block verwenden
Sathe_Nagaraja