2011-02-10 14 views
1

私の主なスレッドから、イメージローダーメソッドメソッド-A(下記)を起動します。問題は、新しいメソッド-Aが呼び出されたときにメソッド-Aが終了していない場合は、画像の読み込みが最初から始まることである。私は、以前方法-呼び出しがまだ仕事をしている間に行われたすべての新しい方法-呼び出しを無効にされて何をしたいのかバックグラウンドスレッド内からグローバル変数(BOOL)を取得/設定する方法は? (Xcode)

...道I(への試み)これは、単純なグローバルな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]; 
} 

ありがとうございます。

+0

変数がグローバルであってはならないことに注意してください。メソッドがインスタンスメソッドであり、イメージの読み込みはおそらくインスタンスによって格納/参照されるイメージを参照するため、インスタンス変数にする必要があります。 –

+0

@変数とマルチスレッドの正確な仕組みについてはっきりと理解していないので、この情報には大変感謝しています。 – m0rtimer

答えて

1

は、この方法を変更してください:

-(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]; 
} 
+0

こんにちは、あなたの素早い答えに感謝します。私はこの方法で同期化された(自己)ものを詳しく教えてください。 – m0rtimer

+0

http://stackoverflow.com/questions/554270/iphone-use-of-mutexes-with-asynchronous-url-requests – Max

+0

基本的に@synchronized(self)は他のすべてのスレッドのメソッドをブロックします – Max

1

Method-aに設定すると、あなたはセッターを呼び出して、そのスレッドをBOOLに設定します。

それを行う方法は次のとおりです。- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait

+0

トーマスクイックに感謝します。それは設定をカバーします。変数の取得はどうですか?それとも、そのまま現実にできるか? – m0rtimer

+0

私はそれが可能だと思います。 NSLockが解決できるデッドロック(複数のスレッドが同じivarにアクセスする)については注意が必要です。あなたがアプリだとは分かりませんが、スレッドからivarsを設定し、取得する場合は、多くの問題があります。多分あなたはデザインだと再確認しますか?それがやむを得ない場合は、マルチスレッドの目的を壊してしまうので、あまり頻繁ではないようにしてください。 –

2

を追加で複数のスレッドがその変数に書き込むことができる場合は、インスタンス変数またはグローバル変数です。同時に、コードのその部分をロックする必要があります。例えば、

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

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

はのは、そのメソッドの2つの実行スレッドAとBで同時に起こり、そしてAは最初のロックを取得し、そのBが解放されるロックを待ちスレッドとしましょう。 Aの観点からは、imageLoaderBusy == NOが返されず、imageLoaderBusy = YESに設定され、ロックが解除されます。

ロックが解除されているため、スレッドBは実行を開始できます。これは、imageLoaderBusyをチェックし、スレッドAがYESに設定しているので、この方法は、スレッドBに直ちに返す

スレッドAは、画像をロードするために進み、NOimageLoaderBusyを設定します。

これは、メソッドがあるスレッドで再び呼び出された場合、そのメソッドは実行され、画像を再びにロードすることに注意してください。それがあなたの意図する行動かどうかはわかりません。そうでない場合は、イメージが既に読み込まれているかどうかを確認するもう1つのチェックが必要になります。たとえば、

-(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は、他のスレッドがすでにビジー状態であった/既にイメージをロードしていることに気付く前に、すべてのイメージがロードされるまで待たなければなりません。

関連する問題