如何正确使用 nsoperationqueue 的 autoreleasepool

发布于 2024-10-09 23:31:11 字数 638 浏览 6 评论 0原文

我有一个正在重构的应用程序,我刚刚实现了多线程,以便 UI 可以运行得更流畅。在 iPhone 模拟器中,我没有遇到任何泄漏,但在运行 iOS 4.2 的 iPhone 3G 上进行测试时,出现了内存泄漏。我已经做了很多搜索来使用操作队列实现自动释放池的正确方法,我们将非常感谢您的帮助。

我在我的视图控制器中创建了一个 nsoperationqueue

- (void)loadData
{
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  NSOperationQueue *queue = [NSOperationQueue new];  // creates multithread for loading data without slowing UI
  NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(firstRun) object:nil];

  [queue addOperation:operation];
  [operation release];
  [queue release];
  [pool release];
}

I have an app that I am refactoring and I just implemented multithreading so that the UI may run smoother. In the iphone simulator I don't get any leaks but testing on my iPhone 3G running on iOS 4.2 I get a memory leak. I have done a lot of searching for the correct way to implement an autoreleasepool with an operationqueue, help will be greatly appreciated.

I have created an nsoperationqueue in my viewcontroller as such

- (void)loadData
{
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  NSOperationQueue *queue = [NSOperationQueue new];  // creates multithread for loading data without slowing UI
  NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(firstRun) object:nil];

  [queue addOperation:operation];
  [operation release];
  [queue release];
  [pool release];
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

神经暖 2024-10-16 23:31:11

首先,您不应该只是创建然后释放队列。更自然的做法是创建该队列作为类的 ivars 之一,然后在视图控制器消失时释放它(您还可以取消任何挂起的操作并取消/等待任何正在运行的操作完成)。

其次,您不需要在创建操作并将其添加到队列中的方法中使用自动释放池,因为该方法是从主线程调用的。相反,您需要对象实际调用的方法中的自动释放池(这可能在另一个线程上运行)。

因此,您可能有以下内容(假设您将队列命名为 ivarqueue_):

- (void)viewDidLoad
{
  [super viewDidLoad];

  if( !queue_ ) queue_ = [[NSOperationQueue alloc] init];
  // other view loading code
}

- (void)loadData
{
  NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(firstRun) object:nil];
  [queue_ addOperation:operation];
  [operation release];
}

- (void)firstRun
{
  // Here we may run on another thread, so 1) we need an autorelease pool; and
  // 2) we need to make sure we don't do anything that requires a runloop
  NSAutoreleasePool* threadPool = [NSAutoreleasePool new];

  // do long-running things

  [threadPool drain];
}

- (void)dealloc
{
  if( queue_ ) {
    [queue_ setSuspended:YES];
    [queue_ cancelAllOperations];
    // you need to decide if you need to handle running operations
    // reasonably, but don't wait here because that may block the
    // main thread
    [queue_ release];
  }
  // other dealloc stuff
  [super dealloc];
}

您还可以按需初始化队列,因此不必在 viewDidLoad 中初始化,而是检查其存在,并在需要时在要添加操作的任何地方进行初始化。这可能包含在它自己的方法调用中,但是这里的延迟初始化可能并不是真正必要的,因为队列非常轻量级。

First, you shouldn't just create and then release the queue. It's more natural to create that queue as one of your class's ivars and then release it when your view controller goes away (you can also cancel up any pending operations and cancel/wait for any running operations to complete).

Second, you don't need the autorelease pool in the method that creates the operation and adds it in the queue since that method is being called from the main thread. Instead, you need the autorelease pool from the method your object actually calls (this is what may be running on another thread).

So, you might have the following (assuming you name your queue ivar queue_):

- (void)viewDidLoad
{
  [super viewDidLoad];

  if( !queue_ ) queue_ = [[NSOperationQueue alloc] init];
  // other view loading code
}

- (void)loadData
{
  NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(firstRun) object:nil];
  [queue_ addOperation:operation];
  [operation release];
}

- (void)firstRun
{
  // Here we may run on another thread, so 1) we need an autorelease pool; and
  // 2) we need to make sure we don't do anything that requires a runloop
  NSAutoreleasePool* threadPool = [NSAutoreleasePool new];

  // do long-running things

  [threadPool drain];
}

- (void)dealloc
{
  if( queue_ ) {
    [queue_ setSuspended:YES];
    [queue_ cancelAllOperations];
    // you need to decide if you need to handle running operations
    // reasonably, but don't wait here because that may block the
    // main thread
    [queue_ release];
  }
  // other dealloc stuff
  [super dealloc];
}

You could also initialize your queue on demand, so instead of initializing in viewDidLoad, check for its existence and initialize if necessary anywhere you'd add an operation. This might be wrapped in a method call of its own, but lazy initialization here probably isn't really necessary as queues are pretty light-weight.

琉璃繁缕 2024-10-16 23:31:11

您应该在 NSOperation 将调用的方法(在本例中为 firstRun)的开头创建一个 NSAutoreleasePool,并在方法的末尾将其耗尽。

You should create an NSAutoreleasePool at the start of the method that the NSOperation will invoke (in this case, firstRun), and drain it at the end of the method.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文