web-dev-qa-db-ja.com

すべてのCALayerのサブレイヤーを削除する

レイヤーのサブレイヤーをすべて削除するのに問題があります。私は現在これを手動で行っていますが、それは不必要な混乱をもたらします。私はグーグルでこれに関する多くのトピックを見つけましたが、答えはありません。

私はこのようなことをしようとしました:

 for(CALayer * rootLayer.sublayersのレイヤー)
 {
 [layer removeFromSublayer]; 
} 

しかし、うまくいきませんでした。

また、rootLayer.sublayersを別のNSArrayにクローンしようとしましたが、結果は同じでした。

何か案は?

編集:

今はうまくいくと思ったが、間違っていた。 CALayersではうまく機能しますが、CATextLayersでは機能しません。何か案は?

59
radex

レイヤーからすべてのサブレイヤーを削除する最も簡単な方法は、サブレイヤープロパティをnilに設定することです。

rootLayer.sublayers = nil;

125
Pascal Bourque

以下が機能するはずです。

for (CALayer *layer in [[rootLayer.sublayers copy] autorelease]) {
    [layer removeFromSuperlayer];
}
33
Ben Gottlieb
[rootLayer.sublayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)];
18
TomH

Swift(ショートバージョン):

layer.sublayers?.forEach { $0.removeFromSuperlayer() }

12
average Joe

_rootLayer.sublayers = nil;_を呼び出すとクラッシュする可能性があります(たとえば、iOS 8でrootLayerを所有するビューでremoveFromSuperviewを2回呼び出す場合)。

正しい方法は次のとおりです。

[[rootLayer.sublayers copy] makeObjectsPerformSelector:@selector(removeFromSuperlayer)]

copyが繰り返し呼び出される配列が変更されないように、removeFromSuperlayerの呼び出しが必要です。そうでない場合は例外が発生します。

5
Kafu

UIViewにサブビューが含まれている場合、self.view.layer.sublayers = nil[layer removeFromSuperlayer]の両方を設定するとクラッシュします。 superLayerからCALayerを削除する最良の方法は、レイヤーの配列を維持することです。たとえば、配列がarrayOfLayersである場合、

UIView.sublayerにレイヤーを追加するたびに、この配列にレイヤーを追加します...

例えば

[arrayOfLayers addObject:layer];
[self.view.layer addSublayer:layer];

削除するだけでこれを呼び出すと、

[arrayOfLayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)];
3
Amit Limje

すべてのサブレイヤーを無差別に削除すると、iOS 7で厄介なクラッシュが発生し、プログラムの実行のずっと後に発生する可能性があります。 _rootLayer.sublayers = nil_と[rootLayer.sublayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)]の両方を使用して、これを徹底的にテストしました。システムが作成したレイヤーが台無しになっている必要があります。

独自のレイヤーの配列を保持し、自分で削除する必要があります。

_[myArrayOfLayersIAddedMyself makeObjectsPerformSelector:@selector(removeFromSuperlayer)];
_
3
Nestor

逆列挙を使用してはどうですか?

NSEnumerator *enumerator = [rootLayer.sublayers reverseObjectEnumerator];
for(CALayer *layer in enumerator) {
    [layer removeFromSuperlayer];
}

順序が正常であれば、サブレイヤーのグループは列挙中に変更されるためです。上記のコードの結果を知りたいです。

2
KatokichiSoft

インデックス0の最初のサブレイヤーだけを削除しようとしましたが、これは機能しました。

- (UITableViewCell *)tableView:(UITableView *)tableView
         cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    if ([cell.contentView.layer.sublayers count] != 0) {
        [[cell.contentView.layer.sublayers objectAtIndex:0] removeFromSuperlayer];
    }
2
zero3nna

私は同じ問題に直面し、多くの解決策を見つけましたが、どれも完璧ではありません。
最後に pnavkの回答より上 アイデアを得ました。そこにあるコードはXamarin/C#ユーザー向けです。
iOSのバージョンは次のとおりです。

Swift 2.3

    if rootLayer.sublayers?.count > 0 {
        rootLayer.sublayers?.forEach {
            if $0.name == "bottomBorderLayer" {
                $0.removeFromSuperlayer()
            }
        }
    }

    let border = CALayer()
    let height = CGFloat(1.0)

    border.borderColor = UIColor.blackColor().CGColor
    border.borderWidth = height

    border.frame = CGRectMake(0, self.frame.size.height - height, self.frame.size.width, self.frame.size.height)

    border.name = "bottomBorderLayer"
    rootLayer.addSublayer(border)
    rootLayer.masksToBounds = true


Objective-C

if (rootLayer.sublayers.count > 0) {
    for (CALayer *layer in rootLayer.sublayers) {
        if ([layer.name isEqualToString:@"bottomBorderLayer"]) {
            [layer removeFromSuperlayer];
        }
    }
}

CALayer *border = [[CALayer alloc] init];
CGFloat height = 1.0;

border.borderColor = [UIColor blackColor].CGColor;
border.borderWidth = height;

border.frame = CGRectMake(0, self.view.frame.size.height - height, self.view.frame.size.width, self.view.frame.size.height);
border.name = @"bottomBorderLayer";
[rootLayer addSublayer:border];
rootLayer.masksToBounds = TRUE;

上記のコードは、下の境界線でのみ機能します。要件に応じて、境界側を変更できます。
ここで、レイヤーをコントローラーに追加する前に、forループを実行して、境界線が既に適用されているかどうかを確認しました。
以前に追加された境界を識別するために、CALayerのnameプロパティを使用します。そして、サブレイヤーから削除する前にそのレイヤーを比較します。
nameプロパティを使用する前に同じコードを試しましたが、ランダムにクラッシュします。ただし、nameプロパティを使用し、削除する前に名前を比較すると、クラッシュの問題は解決します。

これが誰かの助けになることを願っています。

1
Er. Vihar

Xamarin/C#でこれを行う必要がありました。 UITableViewCellに境界線用のCAShapeLayersがいくつかありました。上記のすべてのオプション(配列をコピーしてからレイヤーを削除するなど、クラッシュが発生しました)。私のために働いたアプローチ:

CALayerを追加するときに、名前を付けました:

    var border = new CALayer();
    border.BackgroundColor = color.CGColor;
    border.Frame = new  CGRect(x, y, width, height);
    border.Name = "borderLayerName";
    Layer.AddSublayer(border);

PrepareForReuseUITableViewCellで、SubLayersプロパティのコピーを作成し、以前に割り当てた名前に一致するものをすべて削除しました。

    CALayer[] copy = new CALayer[Layer.Sublayers.Length];
    Layer.Sublayers.CopyTo(copy, 0);
    copy.FirstOrDefault(l => l.Name == "borderLayerName")?.RemoveFromSuperLayer();

クラッシュしません。

お役に立てれば!

1
pnavk