9

画面から待機ビューを削除しているときに、アプリがクラッシュすることがあります。以下のコードを改善する方法を教えてください。


待機ビューは、アプリがサーバーから何かをダウンロードしているときにのみ呼び出されます。ダウンロードが完了したら、removeWaitViewメソッドを呼び出します。

例外タイプ:NSGenericException

理由: 列挙中にコレクションが変更されました。

+(void) removeWaitView:(UIView *) view{
    NSLog(@"Shared->removeWaitView:");
    UIView *temp=nil;
    temp=[view viewWithTag:kWaitViewTag];
    if (temp!=nil) {
        [temp removeFromSuperview];
    }
}

私のwaitview追加コードは

 +(void) showWaitViewInView:(UIView *)view withText:(NSString *)text{
   NSLog(@"Shared->showWaitViewWithtag");
   UIView *temp=nil;
   temp=[view viewWithTag:kWaitViewTag];
   if (temp!=nil)
   {
       return;
   }
   //width 110 height 40
   WaitViewByIqbal *waitView=[[WaitViewByIqbal alloc] initWithFrame:CGRectMake(0,0,90,35)];
   waitView.center=CGPointMake(view.frame.size.width/2,(view.frame.size. height/2) -15); 
   waitView.tag=kWaitViewTag;    // waitView.waitLabel.text=text;
   [view addSubview:waitView];
   [waitView release]; 
}
4

3 に答える 3

18

例外は非常に明確です - コレクション (この場合は配列のようなもの) が列挙されている間に変更されています。

この特定のケースでは、レイヤーの配列、またはより適切に言えば、UIViewそのインスタンスはすべてレイヤーによってバックアップされています。

removeFromSuperviewまたはを呼び出すと、変更が行われますaddSubview。列挙は、再描画中にいつでも発生する可能性があります。

私の推測では、メイン スレッドからメソッドを呼び出しておらず、メイン スレッドが現在再描画中であるため、競合状態が発生します。

解決策: これらのメソッドは、メイン スレッドからのみ呼び出してください。

于 2013-02-13T13:21:53.643 に答える
6

配列のコピーを取得する必要があるため、コードが配列を列挙している間に配列が変更される可能性はありません。もちろん、これにより、ミューテーションの結果として新しいアイテムが追加される可能性が残るため、列挙ではその 1 つの配列アイテムが失われます。質問のタイトルに固有の例を次に示します。

[[viewLayer.sublayers copy] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
            CALayer * subLayer = obj;
            if(subLayer == theLayerToBeDeleted){
                [subLayer removeFromSuperlayer];
            }

        }];
于 2015-09-05T08:18:41.717 に答える
3

waitView の兄弟 (superView のサブビュー) を繰り返し処理しているときに、waitView を追加または削除している可能性があります。どのメソッドが呼び出されるかremoveWaitViewshowWaitInView確認し、呼び出し元のメソッドが待機ビューの兄弟 (waitView のスーパービューのサブビュー) を反復する for ループ内から show/remove 待機ビュー メソッドを呼び出さないことを確認します。

于 2013-02-13T13:25:34.163 に答える