Andrew a répondu à votre principale question selon laquelle, oui, votre piscine d'autorease sera drainée à chaque cycle de la boucle de course principale. Donc, tous les objets d'autorease créés dans viewDidLoad
Peut être rapidement vidé lorsque vous revenez à la boucle de course principale. Ils ne seront certainement pas conservés "avant la résiliation de la demande".
Mais nous devons être prudents: vous supposez clairement que ces objets sont ajoutés à un pool d'autorease. Quelques mises en garde à cette hypothèse:
Dans le passé (et toujours requis pour l'interopérabilité ARC-MRC), lors du retour d'objets de méthodes dont les noms n'ont pas commencé alloc
, new
, copy
, ou mutableCopy
, ces objets n'auraient eu des objets d'autorease, ne traitent que lorsque le pool d'autorease était drainé (c'est-à-dire lorsque vous avez renoncé à la boucle d'exécution).
Mais l'arc est devenu plus intelligent de minimiser le besoin de piscines d'autorease (voir http://rentzsch.tumblr.com/post/75082194868/arcs-fast-autorelease, qui discute callerAcceptsFastAutorelease
, maintenant appelé callerAcceptsOptimizedReturn
invoqué par prepareOptimizedReturn
), donc vous ne verrez souvent pas cela autorelease
comportement. Ainsi, si la bibliothèque et l'appelant utilisent l'arc, les objets peuvent ne pas être placés dans le pool d'autorelease, mais l'arc les libérera intelligemment immédiatement s'ils ne sont pas nécessaires.
Avec des projets d'arc contemporains, les pools d'autorease ne sont généralement pas nécessaires. Mais certains cas spéciaux, on peut toujours bénéficier de l'utilisation de pools d'autorease. Je décrirai l'un de ces cas ci-dessous.
Considérez le code suivant:
#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
Le code suivant ajoutera 500 000 objets au pool d'autorelease, qui ne sera drainé que lorsque je reviendrai à la boucle d'exécution:
Dans ce cas, vous pouvez utiliser une piscine d'autorease pour minimiser la marque élevée de l'eau:
@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
En bout de ligne, avec l'arc, il n'est pas toujours évident lorsqu'il a utilisé un objet Autorelease et lorsqu'il le libère explicitement lorsque la variable tombe de la portée. Vous pouvez toujours le confirmer en examinant le comportement dans les instruments.
En passant, je me méfierais de tirer trop de conclusions générales de gestion de la mémoire lors de l'utilisation du NSString
classe, car elle a été très optimisée et n'est pas toujours conforme aux pratiques de gestion de la mémoire standard.