Как получить / установить глобальную переменную (BOOL) из фонового потока?(Xcode) - PullRequest
1 голос
/ 10 февраля 2011

Из основного потока я запускаю метод загрузки изображений method-A (ниже).Проблема в том, что, если method-A не завершен во время нового вызова method-A , загрузка изображения начинается с начала.

Я хочу аннулировать любые новые method-A вызовы, сделанные во время предыдущего method-A вызов все еще работает ... Способ, которым я (пытаюсь) сделать это сейчас, состоит в том, чтобы иметь простую глобальную переменную BOOL (BOOL imageLoaderBusy) и использовать ее для отслеживания, если method-A все еще работает или нет (как показано ниже).

Проблема в том, что переменная иногда игнорируется, и новые вызовы method-A нежелательно запускаются ... Я не знаю.Может быть, есть какой-то особый способ создания глобальных переменных, чтобы сделать их доступными / действительными для нескольких потоков?

Может кто-нибудь сказать, что я делаю неправильно?Спасибо.

//Method-A called like this:

[self performSelectorInBackground:@selector(loadPagesWithGraphics:) withObject:nil];


//Method-A

-(IBAction)loadPagesWithGraphics:(id)sender{

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

    if(!imageLoaderBusy){

    imageLoaderBusy = YES;

        // Load Images

        }

       imageLoaderBusy = NO;

       [arPool release];
}

Заранее спасибо.

Ответы [ 3 ]

2 голосов
/ 10 февраля 2011

Независимо от того, является ли переменная экземпляром переменной или глобальной переменной, если несколько потоков могут выполнять запись в эту переменную одновременно, вам необходимо заблокировать этот раздел кода. Например,

-(IBAction)loadPagesWithGraphics:(id)sender{
    @synchronized(self) {
        if (imageLoaderBusy) return;
        imageLoaderBusy = YES;
    }

    NSAutoreleasePool *arPool = [[NSAutoreleasePool alloc] init];
    // Load Images
    imageLoaderBusy = NO;
    [arPool release];
}

Допустим, два выполнения этого метода происходят одновременно в потоках A и B, и A сначала получает блокировку, поэтому поток B ожидает снятия блокировки. С точки зрения A, imageLoaderBusy == NO, поэтому он не возвращает, устанавливает imageLoaderBusy = YES и снимает блокировку.

Поскольку блокировка снята, поток B может начать выполнение. Он проверяет imageLoaderBusy и, поскольку поток A установил его на YES, метод немедленно возвращается в поток B.

Поток A приступает к загрузке изображений и устанавливает imageLoaderBusy в NO.

Обратите внимание, что это означает, что если метод вызывается снова в каком-то потоке, он будет выполнен и снова загрузит изображения . Я не уверен, что это ваше намерение; если это не так, вам потребуется еще одна проверка, чтобы определить, загружены ли уже изображения. Например,

-(IBAction)loadPagesWithGraphics:(id)sender{
    if (imagesHaveBeenLoaded) return;

    @synchronized(self) {
        if (imageLoaderBusy) return;
        imageLoaderBusy = YES;
    }

    NSAutoreleasePool *arPool = [[NSAutoreleasePool alloc] init];
    // Load Images
    [arPool release];

    imageLoaderBusy = NO; // not strictly necessary
    imagesHaveBeenLoaded = YES;
}

Вам не нужно иметь весь метод внутри блока @synchronize. Фактически, критические секции обычно должны быть небольшими, особенно если блокировка применяется ко всему объекту (self). Если весь метод был критическим разделом, поток B должен был бы подождать, пока все изображения загрузятся, прежде чем заметить, что другой поток уже занят / уже загрузил изображения.

1 голос
/ 10 февраля 2011

Попробуйте изменить это так:

-(IBAction)loadPagesWithGraphics:(id)sender{
    if( imagesDidLoad )  return;

    @synchronized(self) {

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

        // Load Images

       [arPool release];

       //set global ivar
       imagesDidLoad = YES;
   }
}

и в методе-А

добавить

-(void) methodA {
    if( !imagesDidLoad )
       [self performSelectorInBackground:@selector(loadPagesWithGraphics:) withObject:nil];
}
1 голос
/ 10 февраля 2011

in Method-a вызовите сеттер в вашем основном потоке, чтобы установить это BOOL.

Метод для этого: - (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...