如何从后台线程中获取/设置全局变量(BOOL)? (Xcode中)

时间:2011-02-10 09:11:45

标签: iphone objective-c multithreading xcode ios

从我的主线程中,我启动了一个图像加载器方法方法-A (下面)。问题是,如果方法-A 在进行新的方法-A 调用时未完成,则图像加载从头开始。

我想要做的是,取消在上一个 方法-A时进行的任何 方法-A 调用调用仍在工作......我(尝试)现在这样做的方法是使用一个简单的全局BOOL变量(BOOL imageLoaderBusy)并使用它来跟踪方法-A 仍在工作或不工作(如下所示)。

问题是,变量似乎有时会被忽略,并且新的方法-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 个答案:

答案 0 :(得分:2)

无论变量是实例变量还是全局变量,如果多个线程可以同时写入该变量,则需要锁定该部分代码。例如,

-(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 :(得分:1)

Method-a中的

在您的主要线程上调用一个setter来设置BOOL

执行此操作的方法是:- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait

答案 2 :(得分:1)

尝试改变这种方式:

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

    @synchronized(self) {

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

        // Load Images

       [arPool release];

       //set global ivar
       imagesDidLoad = YES;
   }
}

和方法-A

添加

-(void) methodA {
    if( !imagesDidLoad )
       [self performSelectorInBackground:@selector(loadPagesWithGraphics:) withObject:nil];
}