Ich bin etwas verwirrt über die Blockverwendung in Objective-C. Ich verwende derzeit ARC und habe ziemlich viele Blöcke in meiner App, die sich derzeit immer auf self
die schwache Referenz beziehen. self
Kann dies die Ursache dafür sein, dass diese Blöcke erhalten bleiben und nicht freigegeben werden? Die Frage ist, sollte ich immer eine weak
Referenz von self
in einem Block verwenden?
-(void)handleNewerData:(NSArray *)arr
{
ProcessOperation *operation =
[[ProcessOperation alloc] initWithDataToProcess:arr
completion:^(NSMutableArray *rows) {
dispatch_async(dispatch_get_main_queue(), ^{
[self updateFeed:arr rows:rows];
});
}];
[dataProcessQueue addOperation:operation];
}
ProcessOperation.h
@interface ProcessOperation : NSOperation
{
NSMutableArray *dataArr;
NSMutableArray *rowHeightsArr;
void (^callback)(NSMutableArray *rows);
}
ProcessOperation.m
-(id)initWithDataToProcess:(NSArray *)data completion:(void (^)(NSMutableArray *rows))cb{
if(self =[super init]){
dataArr = [NSMutableArray arrayWithArray:data];
rowHeightsArr = [NSMutableArray new];
callback = cb;
}
return self;
}
- (void)main {
@autoreleasepool {
...
callback(rowHeightsArr);
}
}
ios
iphone
objective-c
automatic-ref-counting
weak-references
the_critic
quelle
quelle
Antworten:
Es hilft, sich nicht auf die
strong
oder einenweak
Teil der Diskussion zu konzentrieren. Konzentrieren Sie sich stattdessen auf den Fahrradteil .A beibehält Zyklus eine Schleife ist, was geschieht , wenn das Objekt A Objekt B behält, und Objekt B behält Objekt A. In dieser Situation , wenn ein Objekt freigegeben wird:
Somit bleiben diese beiden Objekte während der gesamten Laufzeit des Programms im Speicher, obwohl sie freigegeben werden sollten, wenn alles ordnungsgemäß funktioniert.
Wir machen uns also Sorgen, Zyklen beizubehalten , und es gibt nichts an Blöcken an und für sich, die diese Zyklen erzeugen. Dies ist zum Beispiel kein Problem:
Der Block behält den Block bei, behält ihn
self
jedochself
nicht bei. Wenn der eine oder andere freigegeben wird, wird kein Zyklus erstellt und alles wird freigegeben, wie es sollte.Wo Sie in Schwierigkeiten geraten, ist so etwas wie:
Jetzt hat Ihr Objekt (
self
) einen explizitenstrong
Verweis auf den Block. Und der Block hat einen impliziten starken Bezug zuself
. Das ist ein Zyklus, und jetzt wird keines der Objekte ordnungsgemäß freigegeben.Da in einer solchen Situation
self
per Definition bereits einstrong
Verweis auf den Block vorhanden ist, ist es normalerweise am einfachsten, einen explizit schwachen Verweis aufself
den zu verwendenden Block zu erstellen:Dies sollte jedoch nicht das Standardmuster sein, dem Sie beim Umgang mit aufrufenden Blöcken folgen
self
! Dies sollte nur verwendet werden, um einen Haltezyklus zwischen self und dem Block zu unterbrechen. Wenn Sie dieses Muster überall anwenden würden, laufen Sie Gefahr, einen Block an etwas zu übergeben, das ausgeführt wurde, nachdemself
die Zuordnung aufgehoben wurde.quelle
-setCompleteionBlockWithSuccess:failure:
Methode ab. Wennpaginator
es sich jedoch im Besitz vonViewController
befindet und diese Blöcke nicht aufgerufen werden, nachdemViewController
sie freigegeben wurden, ist die Verwendung einer__weak
Referenz der sichere Schritt (daself
das Objekt gehört, dem die Blöcke gehören, und daher wahrscheinlich immer noch vorhanden ist, wenn die Blöcke es aufrufen obwohl sie es nicht behalten). Aber das sind viele "Wenn". Es kommt wirklich darauf an, was das tun soll.MyObject
undSomeOtherObject
beide besitzen den Block. Aber weil die Referenz BlockadeMyObject
istweak
, wird der Block nicht selbstMyObject
. So , während der Block garantiert wird solange bestehen entwederMyObject
oderSomeOtherObject
existieren, gibt es keine Garantie , dassMyObject
solange der Block nicht vorhanden ist wird.MyObject
kann vollständig freigegeben werden und solangeSomeOtherObject
der Block noch vorhanden ist, bleibt der Block bestehen.Sie müssen nicht immer eine schwache Referenz verwenden. Wenn Ihr Block nicht beibehalten, sondern ausgeführt und dann verworfen wird, können Sie sich selbst stark erfassen, da dadurch kein Aufbewahrungszyklus erstellt wird. In einigen Fällen möchten Sie sogar, dass der Block das Selbst bis zur Fertigstellung des Blocks hält, damit die Zuordnung nicht vorzeitig aufgehoben wird. Wenn Sie den Block jedoch stark und innerhalb von Capture Self erfassen, wird ein Aufbewahrungszyklus erstellt.
quelle
Ich stimme @jemmons voll und ganz zu:
Um dieses Problem zu lösen, kann man eine starke Referenz über das
weakSelf
Innere des Blocks definieren:quelle
->
) zugreifen , in dem Sie sicherstellen möchten, dass Sie tatsächlich eine gültige Referenz erhalten, und diese kontinuierlich über die gesamte Gruppe von Operationen hinweg aufbewahren, z. B.if ( strongSelf ) { /* several operations */ }
Wie Leo betont, würde der Code, den Sie Ihrer Frage hinzugefügt haben, keinen starken Referenzzyklus vorschlagen (auch bekannt als Zyklus beibehalten). Ein betriebsbedingtes Problem, das einen starken Referenzzyklus verursachen könnte, wäre, wenn die Operation nicht freigegeben wird. Ihr Code-Snippet weist zwar darauf hin, dass Sie Ihren Vorgang nicht als gleichzeitig definiert haben, aber wenn Sie dies getan haben, wird er nicht freigegeben, wenn Sie nie gepostet
isFinished
haben oder wenn Sie zirkuläre Abhängigkeiten oder ähnliches hatten. Und wenn der Vorgang nicht freigegeben wird, wird auch der View Controller nicht freigegeben. Ich würde vorschlagen, einen Haltepunkt oderNSLog
diedealloc
Methode Ihres Vorgangs hinzuzufügen und zu bestätigen, dass dieser aufgerufen wird.Du sagtest:
Die Probleme mit dem Aufbewahrungszyklus (starker Referenzzyklus), die bei Blöcken auftreten, sind genau wie die Probleme mit dem Aufbewahrungszyklus, mit denen Sie vertraut sind. Ein Block behält starke Verweise auf Objekte bei, die innerhalb des Blocks angezeigt werden, und gibt diese starken Verweise erst frei, wenn der Block selbst freigegeben wird. Wenn also Blockreferenzen
self
oder sogar nur eine Instanzvariable von referenzierenself
, die einen starken Bezug zu self beibehält, wird dies erst aufgelöst, wenn der Block freigegeben wird (oder in diesem Fall, bis dieNSOperation
Unterklasse freigegeben wird).Weitere Informationen finden Sie im Abschnitt Vermeiden starker Referenzzyklen beim Erfassen von Selbst im Dokument Programmieren mit Objective-C: Arbeiten mit Blöcken .
Wenn Ihr View Controller immer noch nicht freigegeben wird, müssen Sie lediglich feststellen, wo sich die ungelöste starke Referenz befindet (vorausgesetzt, Sie haben bestätigt, dass die Zuordnung
NSOperation
aufgehoben wird). Ein häufiges Beispiel ist die Verwendung einer WiederholungNSTimer
. Oder ein benutzerdefiniertesdelegate
oder anderes Objekt, das fälschlicherweise einestrong
Referenz verwaltet. Sie können häufig Instrumente verwenden, um festzustellen, wo Objekte ihre starken Referenzen erhalten, z.Oder in Xcode 5:
quelle
Einige Erklärungen ignorieren eine Bedingung bezüglich des Aufbewahrungszyklus. [Wenn eine Gruppe von Objekten durch einen Kreis starker Beziehungen verbunden ist, halten sie sich gegenseitig am Leben, auch wenn es keine starken Referenzen von außerhalb der Gruppe gibt.] Weitere Informationen finden Sie im Dokument
quelle
So können Sie das Selbst innerhalb des Blocks verwenden:
// Aufruf des Blocks
quelle