Frage Aufruf von super bei der Implementierung eines Objective-C-Blocks


Ruft eine Methode auf Super unterstützt bei der Implementierung eines Objective-C-Blocks?

Als ich eine Methode angerufen habe Super ein EXC_BAD_ACCESS Fehler würde aber ausgelöst, sobald ich diese Anrufe geändert habe [super methodToCall] zu [self methodToCall] und ließ die Nachricht die Responder-Kette nach oben gehen, es hat gut funktioniert.

Es gibt keine Implementierung von -methodToCall in der Instanz der Klasse, in der der Block existiert, aber es gibt eine in der Oberklasse (dh die Klasse, von der selbst erbt).

Ich bin nur neugierig auf die Details, warum das Anrufen einer Methode auf Super innerhalb der Implementierung eines Blocks (technisch) ein Problem war, so dass ich es in Zukunft vermeiden kann. Ich habe den Verdacht, dass es damit zusammenhängt, wie die Variablen im Block und etwas über den Stack und den Heap erfasst werden, aber ich habe wirklich keine konkrete Idee.

Hinweis: Der Blockimplementierungscode wird bis wenige Sekunden nach dem Speichern des Blocks in einer Eigenschaft aufgerufen, die von der Eigenschaft verwendet wird Kopieren Ich denke also nicht, dass es ein Problem mit dem Lebenszyklus des Blocks ist, dass alles gut aussieht. Auch dies stürzte nur auf dem iPhone-Gerät (3G), aber es funktionierte ohne Absturz im iPhone Simulator.

Ergebnisse in EXC_BAD_ACCESS:

[self retrieveItemsForId:idString completionHandler:^(NSError *error) {
 if (!error) {
  [super didRetrieveItems];
 } else {
  [super errorRetrievingItems];
 }
}];

Funktioniert perfekt, Implementierungen von -didRetrieveItems und -errorRetrievingItems sind in der Super-Klasse.

[self retrieveItemsForId:idString completionHandler:^(NSError *error) {

 if (!error) {
  [self didRetrieveItems];
 } else {
  [self errorRetrievingItems];
 }
}];

11
2017-12-12 03:01


Ursprung


Antworten:


Technisch gesehen ist dies ein Problem mit der Objective-C-Laufzeit und der zugrundeliegenden Mechanik, wie Anrufe angehen super tatsächlich arbeiten. Grundsätzlich erfassen sie sowohl das Objekt, das der Empfänger der Nachricht ist (self in allen Fällen) und die Klasse, die die spezifische Version der Methode implementiert (die Oberklasse der Klasse, in der die Methodenimplementierung stattfindet). Da ein Großteil der Vorbereitung für eine solche Nachrichtensendung zur Kompilierzeit und nicht zur Laufzeit erfolgt, wäre ich nicht überrascht, wenn sie schlecht mit Blöcken interagiert hätte.

Ich würde nachsehen, ob self ist immer noch gültig, wenn die Nachricht gesendet werden soll. Normalerweise werden alle in einem Block referenzierten Objekte automatisch beibehalten. Schon seit super funktioniert ein bisschen anders, könnte das bedeuten self wird nicht beibehalten, wie man es erwarten würde. Eine einfache Möglichkeit, dies zu überprüfen, wäre die Verwendung der Anrufe an super wie ursprünglich geschrieben, und leckt einfach das Objekt, das als bezeichnet wird selfund sehen, ob es funktioniert. Wenn sich dies als Problem herausstellt, müssen Sie möglicherweise eine Dummy-Referenz einfügen self innerhalb des Blocks, um diese automatische Speicherverwaltung zu erhalten.

Im engeren Sinne bin ich mir jedoch nicht sicher, ob Sie sich darauf verlassen können, dass dies für immer und ewig funktioniert. Obwohl Blöcke den aktuellen Laufzeitstatus erfassen können, ist es aus OOP-Perspektive nicht sinnvoll, dass sie die Kapselung unterbrechen und Superklassenimplementierungen aufrufen, da sie hierarchisch sind Niveau bei denen Methoden implementiert werden, sollten für jeden externen Aufrufcode undurchsichtig sein. Ich würde versuchen, eine andere Lösung zu finden, die nicht von der Vererbungshierarchie abhängt.


11
2017-12-12 03:12



Ergebnisse in EXC_BAD_ACCESS:

[self retrieveItemsForId:idString completionHandler:^(NSError *error) {
 if (!error) {
  [super didRetrieveItems];
 } else {
  [super errorRetrievingItems];
 }
}];

Wahrscheinlich aufgrund eines Fehlers im Compiler; versuche es hinzuzufügen [self class]; oder irgendein anderer Methodenaufruf zu self in diesem Block und es wird wahrscheinlich funktionieren.

Funktioniert perfekt, Implementierungen von -didRetrieveItems und -errorRetrievingItems sind in der Super-Klasse.

[self retrieveItemsForId:idString completionHandler:^(NSError *error) {

 if (!error) {
  [self didRetrieveItems];
 } else {
  [self errorRetrievingItems];
 }
}];

Ich denke, Sie sind vielleicht verwirrt über einen der grundlegenden Aspekte der objektorientierten Programmierung. Sie sagen, dass es in Ihrer Klasse keine Implementierungen dieser Methoden gibt, sie existieren nur in der Oberklasse.

Aufgrund der Vererbung reagiert Ihre Klasse auch effektiv auf diese Methodenaufrufe. Rufen Sie sie einfach wie oben beschrieben an self. Es wird funktionieren und finden Sie genau wie Sie es tun sollten!


8
2017-12-12 03:30