Andrew respondeu à sua principal pergunta que, sim, seu pool de autorlease será drenado em todos os ciclos do loop de corrida principal. Portanto, quaisquer objetos autorlease criados em viewDidLoad
Pode ser drenado imediatamente quando você renderá de volta ao loop de corrida principal. Eles certamente não serão mantidos "até o término do aplicativo".
Mas devemos ter cuidado: você está claramente assumindo que esses objetos estão sendo adicionados a um pool de autorlease. Algumas advertências para esta suposição:
No passado (e ainda necessário para a interoperabilidade ARC-MRC), ao devolver objetos de métodos cujos nomes não começaram alloc
, new
, copy
, ou mutableCopy
, esses objetos queriam os objetos, desalocados apenas quando o pool de autorlease foi drenado (ou seja, quando você se rendeu ao loop de corrida).
Mas o ARC ficou mais inteligente em minimizar a necessidade de pools de autorlease (ver http://rentzsch.tumblr.com/post/75082194868/arcs-fast-autorelease, que discute callerAcceptsFastAutorelease
, agora chamado callerAcceptsOptimizedReturn
invocado por prepareOptimizedReturn
), então você geralmente não verá isso autorelease
comportamento. Portanto, se a biblioteca e o chamador estiverem usando o ARC, os objetos não poderão ser colocados no pool de autorlease, mas o ARC os liberará inteligentemente imediatamente, se não forem necessários.
Com projetos de arco contemporâneo, os pools de autorlease geralmente não são necessários. Mas certos casos especiais, ainda é possível se beneficiar do uso de pools automáticos. Vou delinear um desses casos abaixo.
Considere o seguinte código:
#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
O código a seguir adicionará 500.000 objetos ao pool de autorlease, que só serão drenados quando eu ceder ao loop de corrida:
Nesse caso, você pode usar um pool de autorlease para minimizar a marca d'água alta:
@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
Conclusão, com arco, nem sempre é óbvio quando usou um objeto de autorlease e quando o libera explicitamente quando a variável cai do escopo. Você sempre pode confirmar isso examinando o comportamento em instrumentos.
Como um aparte, eu ficaria cauteloso em tirar muitas conclusões gerais de gerenciamento de memória ao usar o NSString
A classe, como foi altamente otimizada e nem sempre está em conformidade com as práticas de gerenciamento de memória padrão.