2010-05-30 4 views
0

У меня есть UIViewController, и в этом контроллере я получаю изображение из источника URL. Изображение загружается в отдельный поток, после которого пользовательский интерфейс обновляется в основном потоке. Этот контроллер отображается в виде страницы в родительском элементе UIScrollView, который предназначен для выпуска контроллеров, которые больше не отображаются.iPhone: проблемы с выпуском UIViewController в многопоточной среде

Когда поток заканчивает получение содержимого до выпуска UIViewController, все работает нормально - но когда пользователь прокручивается на другую страницу до завершения потока, контроллер освобождается, а единственный дескриптор контроллера принадлежит потоку releaseCount контроллера равен 1. Теперь, как только поток истощает NSAutoreleasePool, контроллер получает релизы, потому что releaseCount становится 0. в этот момент моего сбой приложения и я получаю следующее сообщение об ошибке:

Их _WebTryThreadLock (bool), 0x4d99c60: попытался получить веб-блокировку из потока, отличного от основного потока или веб-потока. Это может быть результатом вызова UIKit из вторичного потока. Сбой сейчас ...

Обратный ход показывает, что приложение потерпело крах при вызове [super dealloc], и это имеет смысл, поскольку функция dealloc должна была быть вызвана нитью при сливе пула. Мой вопрос в том, как я могу преодолеть эту ошибку и освободить контроллер без утечки памяти?

Одно из решений, что я попытался было назвать [самостоятельно сохранить] до бассейна сливают так, что retainCount не падает до нуля, а затем, используя следующий код, чтобы освободить контроллер в основном потоке:

[self performSelectorOnMainThread:@selector(autorelease) 
    withObject:nil waitUntilDone:NO]; 

К сожалению, это не сработало. Ниже приведена функция, которая выполняется на резьбе:

- (void)thread_fetchContent { 

    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 

    NSURL *imgURL = [NSURL URLWithString:@"http://www.domain.com/image.png"]; 

    // UIImage *imgHotspot is declared as private - The image is retained 
    // here and released as soon as it is assigned to UIImageView 

    imgHotspot = [[[UIImage alloc] initWithData: 
     [NSData dataWithContentsOfURL: imgURL]] retain]; 

    if ([self retainCount] == 1) { 

     [self retain]; // increment retain count ~ workaround 
     [pool drain]; // drain pool 

     // this doesn't work - i get the same error 

     [self performSelectorOnMainThread:@selector(autorelease) 
      withObject:nil waitUntilDone:NO]; 
    } 

    else { 

     // show fetched image on the main thread - this works fine! 

     [self performSelectorOnMainThread:@selector(showImage) 
      withObject:nil waitUntilDone:NO]; 

     [pool drain]; 
    } 
} 

Пожалуйста, помогите! Заранее спасибо.

ответ

0

Да, это может быть очень сложным, чтобы попытаться сохранить синхронизированный поток. Вариант использования, который вы описываете, идеально подходит для NSOperation. Используя этот подход, вы можете иметь NSOperationQueue как ivar в контроллере и освободить его в методе dealloc контроллеров.

Преимущества, которые видны в представлении диспетчера в scrollView (viewWillAppear или loadView), начинают извлекать изображение с использованием NSOperation, добавленного в NSOperationQueue, если пользователь затем прокручивается до завершения операции и NSOperationQueue , он позаботится о том, чтобы отправить сообщение отмены всем операциям и в целом закрыть все по порядку.

Если это центральный компонент в вашем приложении, который, я думаю, с тех пор, как вы положили мысль на выпуск вещей, которые являются «экраном», я бы рекомендовал, чтобы ваш контроллер отображал «фиктивное изображение» в методе loadVIew и затем запустите операцию выборки в viewDidLoad. Вы можете подклассифицировать NSOperation так, чтобы вы просто отправили ему URL-адрес и позволили ему это сделать.

Я сделал что-то подобное несколько недель назад, когда мне приходилось постоянно запускать операции с резьбой, но с большой вероятностью пользователь мог бы сделать что-то, что заставило их отменить. Эта функциональность «встроена» в NSOperation. NSOperation question

+0

Спасибо! Подход NSOperation был большой помощью - я посмотрел ссылку, которую вы предоставили, и учебник по адресу http: //www.cimgf.com/2008/02/16/cocoa-tutorial-nsoperation-and-nsoperationqueue/- он решил мою проблему :) –