Использование NSAutoreleasePool с NSURLConnection - PullRequest
0 голосов
/ 17 октября 2011

Я пытаюсь следовать примеру XMLPerformance, чтобы создать собственный xml-анализатор. Пока у меня самое трудное время, чтобы автозапускные пулы работали, у меня происходит сбой, как только я воссоздаю пул.

Я сузил проблему до этого теста:

PoolCrashTest.h

#import <SenTestingKit/SenTestingKit.h>

@interface PoolCrashTest : SenTestCase
{
  @private
  NSURLConnection *connection;
  NSAutoreleasePool *downloadAndParsePool;
  BOOL done;
}

@property (nonatomic, retain) NSURLConnection *connection;
@property (nonatomic, assign) NSAutoreleasePool *downloadAndParsePool;

- (void)downloadAndParse:(NSURL *)url;
@end

PoolCrashTest.m

#import "PoolCrashTest.h"

@implementation PoolCrashTest

@synthesize downloadAndParsePool, connection;

- (void)downloadAndParse:(NSURL *)url {
  done = NO;
  self.downloadAndParsePool = [[NSAutoreleasePool alloc] init];
  NSURLRequest *theRequest = [NSURLRequest requestWithURL:url];
  self.connection = [[NSURLConnection alloc] 
                     initWithRequest:theRequest delegate:self];
  if (connection != nil) {
    do {
      [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode 
                               beforeDate:[NSDate distantFuture]];
    } while (!done);
  }
  self.connection = nil;
  [downloadAndParsePool release];
  self.downloadAndParsePool = nil;
}

#pragma mark NSURLConnection Delegate methods

- (void)connection:(NSURLConnection *)connection 
    didReceiveData:(NSData *)data {
  [downloadAndParsePool drain];

сбой после этой строки ^

  self.downloadAndParsePool = [[NSAutoreleasePool alloc] init];
}

- (void)testPoolCrash
{
  NSURL *dumpURL = [NSURL URLWithString:@"file:///some.xml"];

  [NSThread detachNewThreadSelector:@selector(downloadAndParse:) 
                               toTarget:self withObject:dumpURL];
  sleep(10);
}

@end

Может кто-нибудь объяснить, как правильно очищать пул авто-выпуска в делегате NSURLConnection, работающем в потоке?

Я пытался следовать XMLPerformance как можно ближе ... Я нацеливаюсь на Lion, используя в основном настройки проекта по умолчанию.

Ответы [ 2 ]

2 голосов
/ 17 октября 2011

Крейг прав, когда говорит, что вы переиздаваете свой пул. В среде без GC release и drain имеют одинаковый эффект. В среде GC release - это неоперабельный для любого объекта , поэтому вместо него следует использовать drain. Я бы просто использовал drain.

Тем не менее, NSAutoreleasePool объекты на самом деле не вещи, которые вы должны делать свойством своего класса; они будут работать лучше для вас, если вы ограничите их использование лексической областью. Есть несколько способов использовать пул в коде, который вы разместили выше, и этого будет достаточно.

Помните, что при вращении цикла выполнения он будет входить и выходить из вызова, чтобы запустить цикл выполнения в обычных режимах; так что вы можете сделать это вместо:

if (connection != nil) {
  do {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode 
                             beforeDate:[NSDate distantFuture]];
    [pool drain];
  } while (!done);
}

и вы будете сливать любые автоматически выпущенные объекты, созданные в конкретном цикле цикла выполнения. Поскольку обратный вызов делегата соединения будет вызываться из-за этого вызова цикла выполнения, все автоматически выпущенные объекты, созданные в обратном вызове делегата, будут очищены при сливе этого пула.

Если вам это неудобно, вы можете поместить пул в ваш метод делегата в зависимости от того, сколько работы ваш метод делегата может выполнять:

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    // Do whatever work you want here
    [pool drain];
}

И в вашем случае это будет иметь примерно такой же эффект.

Я бы настоятельно рекомендовал сделать что-то похожее на мой первый пример выше и устранить поведение пула авто-выпусков, которое у вас есть сейчас. Хранение NSAutoreleasePool объектов в одной лексической области облегчает все, от отладки до безопасной обработки исключений, когда это становится необходимым.

1 голос
/ 17 октября 2011

Вы перепродаете свой пул.

Я перечитываю ваш вопрос, чтобы убедиться, что я его понимаю, но если вы посмотрите документацию NSAutoreleasePool вы увидите, что release и drain не должны оба использоваться.(Это почти идентично простому вызову release дважды.) Используйте только drain:

В среде со сборщиком мусора нет необходимости в пулах автоматического выпуска.Однако вы можете написать каркас, предназначенный для работы как в сборщике мусора, так и в среде с подсчетом ссылок.В этом случае вы можете использовать пулы автоматического выпуска, чтобы намекнуть сборщику, что сбор может быть целесообразным.В среде сбора мусора отправка сообщения «сток» в пул запускает сборку мусора при необходимости;релиз, однако, не является опцией.В среде с подсчетом ссылок утечка имеет тот же эффект, что и выпуск. Как правило, поэтому вы должны использовать сток вместо выпуска.

Редактировать: Этот предыдущий вопрос может помочь вам понять, как выследует использовать периодически слива NSAutoreleasePool в многопоточной среде.

...