3

ページを作成する広告レイアウトプログラム(NSViewクラスPage)があり、各ページに余白とガター(より多くのNSView)を配置し、次に広告(NSViewクラスAd)を配置します。アプリはデータベースソースから広告を自動的に配置し、各ページに入力する適切なスペースを探します。次に、ユーザーは広告をたとえば4ページから2ページに移動するオプションがあります。また、移動したばかりの広告が0 /になると想定して、手動で広告をフローするか、アプリを自動フローするオプションもあります。 0 x / yの場所、そして他の場所は利用可能なスペースに流れ、現在のページにスペースがない場合は次のページにプッシュされます(移動したばかりの広告のため)。

私が行っていたのは、すべてのページ(masterpageと呼ばれるNSViewのサブビュー)を取得し、それらをループしてすべてのサブビューを配列に入れることでした。その配列をループし、余白とガターをフィルタリングし、広告の場合はスーパービューから削除します。私の考えは、きれいなページから始めて、すべての広告を置き換えることでした。問題は、このエラーが発生し続けることです。

Collection <NSCFArray: 0x1078900> was mutated while being enumerated.

私はこのコードを使用しています:

//loop through all the pages
    for(NSView* thisPage in masterPageSubViews) { 

        //get all the ads on this page
        NSArray* thisPageSubviews = [thisPage subviews];
        for(NSView* thisPageSubview in thisPageSubviews) { 
            if ([[thisPageSubview className] isEqual:@"Ad"]) { 
                [thisPageSubview removeFromSuperview];
            }
        }
    }

なぜこのエラーが発生するのか混乱していると思います。配列内のオブジェクトは、ループ内で作成されているオブジェクトとは別のものだと思いました。

各ページの広告の数は動的であるため、配列を使用せずにスーパービューから広告を削除するにはどうすればよいですか?

4

5 に答える 5

7

エラーが示すように、高速列挙を使用して配列を処理している間は、配列の内容を修正することはできません。removeFromSuperviewスーパービューの配列からビューを削除しますsubviews(これは読みにくい文です!)。これは、配列を列挙しているときに配列を変更していることを意味します。

おそらくもっと良い方法がNSMutableArrayありますが、広告ビューを入力する方法があります。終了したら、スーパービューから自分自身を削除することができます(テストされていないコード、ブラウザに入力してください!)

NSMutableArray *viewsToRemove = [[NSMutableArray alloc] init];
for(NSView* thisPage in masterPageSubViews) 
{           
    //get all the ads on this page         
    NSArray* thisPageSubviews = [thisPage subviews];         
    for(NSView* thisPageSubview in thisPageSubviews)              
        if ([thisPageSubview isMemberOfClass:[Ad class]]) 
            [viewsToRemove addObject:thisPageSubview];                                 
}         
[viewsToRemove makeObjectsPerformSelector:@selector(removeFromSuperview)];
[viewsToRemove release];  
于 2011-11-01T16:09:52.677 に答える
5

上記の答えはかなり高価ですが、それを回避できるのになぜオブジェクトを作成するのですか?そして、より少ないコードで同じことを行うことができます。

while([[superView subviews] count] > 0) {
    [[[superView subviews] objectAtIndex:0] removeFromSuperview];
}

編集:私はObjective CとCocoaを初めて使用するので、ARCなしでコーディングしたことがないので、これがARCなしで機能するかどうかはわかりません。

于 2012-09-24T19:10:13.743 に答える
0
if([[yourView subviews] count] > 0) {
    [[[yourView subviews] objectAtIndex:0] removeFromSuperview];
}

Good Luck !!!
于 2014-01-04T11:20:30.757 に答える
0

少なくとも10.10以降は、コピーを返すため、サブビューで高速列挙を使用できます。

[view.subviews enumerateObjectsUsingBlock:^(NSView * subview, NSUInteger idx, BOOL *stop) {
    [subview removeFromSuperview];
}];
于 2014-11-11T04:48:56.323 に答える
0

クラスのチェックが問題である場合(そして元の質問では問題でした)、列挙子がなくても、バックエンドから問題を解決できます。

NSArray *subs = [myView subviews];
for(NSInteger i=[subs count]-1; i>0; i--){
    if([[subs[i] className]isEqual:@"nameOfClassToDelete"]){
        [subs[i] removeFromSuperviewWithoutNeedingDisplay];
    }
}

私は実際にこのコードを持っています、それは動作します:-)

于 2015-02-19T03:35:41.727 に答える