Andrew hat Ihre Hauptfrage so beantwortet: Ja, Ihr Autorelease-Pool wird bei jedem Zyklus der Hauptlaufschleife geleert.Also alle Autorelease-Objekte, die in erstellt wurden viewDidLoad
kann sofort entleert werden, wenn Sie zur Hauptlaufschleife zurückkehren.Sie werden sicherlich nicht „bis zur Beendigung der Bewerbung“ aufbewahrt.
Aber wir sollten vorsichtig sein:Sie gehen eindeutig davon aus, dass diese Objekte einem Autorelease-Pool hinzugefügt werden.Ein paar Vorbehalte zu dieser Annahme:
In der Vergangenheit (und immer noch für die ARC-MRC-Interoperabilität erforderlich), wenn Objekte von Methoden zurückgegeben wurden, deren Namen nicht mit begannen alloc
, new
, copy
, oder mutableCopy
, diese Objekte würden Objekte automatisch freigeben und nur dann freigegeben, wenn der Autorelease-Pool geleert wurde (d. h.als Sie zur Laufschleife zurückkehrten).
Aber ARC ist bei der Minimierung des Bedarfs an Autorelease-Pools schlauer geworden (siehe http://rentzsch.tumblr.com/post/75082194868/arcs-fast-autorelease, das diskutiert callerAcceptsFastAutorelease
, jetzt genannt callerAcceptsOptimizedReturn
aufgerufen von prepareOptimizedReturn
), sodass Sie dies oft nicht sehen werden autorelease
Verhalten.Wenn also sowohl die Bibliothek als auch der Aufrufer ARC verwenden, werden Objekte möglicherweise nicht im Autorelease-Pool platziert, sondern ARC gibt sie geschickt sofort frei, wenn sie nicht benötigt werden.
Bei modernen ARC-Projekten sind Autorelease-Pools im Allgemeinen nicht erforderlich.In bestimmten Sonderfällen kann die Verwendung von Autorelease-Pools jedoch dennoch von Vorteil sein.Einen dieser Fälle werde ich im Folgenden skizzieren.
Betrachten Sie den folgenden Code:
#import "ViewController.h"
#import <sys/kdebug_signpost.h>
typedef enum : NSUInteger {
InnerLoop = 1,
MainLoop = 2
} MySignPostCodes;
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSURL *fileURL = [[NSBundle mainBundle] URLForResource:@"test" withExtension:@"png"];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
kdebug_signpost_start(MainLoop, 0, 0, 0, 1);
for (int j = 0; j < 500; i++) {
NSData *data = [NSData dataWithContentsOfURL:fileURL];
UIImage *image = [[UIImage alloc] initWithData:data];
NSLog(@"%p", NSStringFromCGSize(image.size)); // so it's not optimized out
[NSThread sleepForTimeInterval:0.01];
}
kdebug_signpost_end(MainLoop, 0, 0, 0, 1);
});
}
@end
Der folgende Code fügt dem Autorelease-Pool 500.000 Objekte hinzu, die erst geleert werden, wenn ich zur Ausführungsschleife zurückkehre:
In diesem Fall könnten Sie einen Autorelease-Pool verwenden, um die Obergrenze zu minimieren:
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSURL *fileURL = [[NSBundle mainBundle] URLForResource:@"test" withExtension:@"png"];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
kdebug_signpost_start(MainLoop, 0, 0, 0, 1);
for (int j = 0; j < 5; j++) {
@autoreleasepool {
kdebug_signpost_start(InnerLoop, 0, 0, 0, 2);
for (long i = 0; i < 100; i++) {
NSData *data = [NSData dataWithContentsOfURL:fileURL];
UIImage *image = [[UIImage alloc] initWithData:data];
NSLog(@"%p", NSStringFromCGSize(image.size)); // so it's not optimized out
[NSThread sleepForTimeInterval:0.01];
}
kdebug_signpost_end(InnerLoop, 0, 0, 0, 2);
}
}
kdebug_signpost_end(MainLoop, 0, 0, 0, 1);
});
}
@end
Unterm Strich ist es bei ARC nicht immer offensichtlich, wann ein Autorelease-Objekt verwendet wurde und wann es es explizit freigibt, wenn die Variable außerhalb des Gültigkeitsbereichs liegt.Sie können dies jederzeit bestätigen, indem Sie das Verhalten in Instruments untersuchen.
Abgesehen davon wäre ich vorsichtig, wenn ich bei der Verwendung von nicht zu viele allgemeine Schlussfolgerungen zur Speicherverwaltung ziehe NSString
Klasse, da sie stark optimiert wurde und nicht immer den Standardpraktiken der Speicherverwaltung entspricht.