65

In an animation I added a lot of sublayers to a view, with:

[self.view.layer addSublayer:layer1];
[self.view.layer addSublayer:layer2];

....

I would like to remove all sublayers with an action. I already tried with this suggestion of a similar question:

rootLayer.sublayers = nil;

but it doesn't work...

Could you help me? Than you!

Upholder Of Truth
  • 4,643
  • 2
  • 13
  • 23
Beppino66
  • 1,709
  • 2
  • 13
  • 15

8 Answers8

156

The sublayers property of a CALayer object returns a copy of the array. Setting it no nil does nothing about the sublayers. This however will do:

for (CALayer *layer in self.view.layer.sublayers) {
    [layer removeFromSuperlayer];
}

Or, in Swift

self.view.layer.sublayers?.forEach { $0.removeFromSuperlayer() }
Svein Halvor Halvorsen
  • 2,474
  • 1
  • 16
  • 14
  • 6
    It seems I am mistaken. You _can_ set the `sublayers` to an array prepopulated with `CALayer` objects. My solution is still correct, though. Also this oneliner should probably work (untested): `[self.view.layer.sublayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)]` – Svein Halvor Halvorsen Jun 25 '12 at 09:15
  • @SveinHalvorHalvorsen That one line does work. Its much cleaner than a loop – catalyst294 Jan 09 '14 at 20:11
  • Plus, it's sometimes problematic to mutate an array while iterating through it. Maybe it happens to work here, but in general it can be problematic. – Rob Dec 04 '14 at 11:28
  • The `sublayers` property of `CALayer` returns a copy. However, so you're not mutating the array you're iterating over. Also, if an element of the array is no longer a sublayer of the layer by the time you call `removeFromSuperLayer` this has no side-effects unless the layer has been added as a sublayer to another layer. – Svein Halvor Halvorsen Dec 04 '14 at 12:10
  • 5
    Although sublayers property of CALayer has "copy" attribute, this code causes crash with more than one sublayer (trying to mutate array while enumerating it). Explicitly copying sublayers array fixes this problem: for (CALayer *sublayer in [rootLayer.sublayers copy]) { [sublayer removeFromSuperlayer]; } – Jovan Stankovic Jul 05 '15 at 17:36
  • 1
    For swift version,it will be better if we can add check of ---- if layer.isKindOfClass(CAShapeLayer) { layer.removeFromSuperlayer() } – Sakshi Feb 29 '16 at 04:58
  • this threw NSGenericException – JLT Jun 02 '16 at 02:40
  • 1
    @JoeBlow I reverted your edits. There is no reason to only remove `CAShapeLayer`. The original question does not mention shape layers, and this arbitrarily restricts the layers removed to one special kind. We want to remove _all_ sublayers. The code above does not crash, and does not mutate the array while iterating. – Svein Halvor Halvorsen Jun 03 '16 at 21:53
  • Big Thanks for you man, a week pass trying to solve this issue. just with your code everything is okay. – Xin Lok Apr 25 '17 at 18:22
  • Like we have `tag` in `view` is there any specific thing to identify specific layer ? – Jack Jul 19 '18 at 07:37
33

Swift 3.0 & Swift 4.0

Set the sublayers property to nil to remove all sublayers from a view.

view.layer.sublayers = nil

also you can add

.removeAll()
Harshil Kotecha
  • 2,846
  • 4
  • 27
  • 41
  • 1
    Worked for me, Dont know any downside of doing this. Should this be used rather than calling removeFromSuperLayer() for each sub layer? May be others can comment. – soan saini Sep 05 '18 at 02:01
22

This worked for me and fixed the crash:

[self.view.layer.sublayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)]

I changed the view with my image UImageview, and the crash is gone.

Samuel Liew
  • 76,741
  • 107
  • 159
  • 260
Hussain1982
  • 301
  • 2
  • 12
5

For swift5 to remove CAShapeLayer from added view

guard let sublayers = self.view.layer.sublayers else { return }

for sublayer in sublayers where sublayer.isKind(of: CAShapeLayer.self) {
        sublayer.removeFromSuperlayer()
}
Hardik Thakkar
  • 15,269
  • 2
  • 94
  • 81
4

Swift 2.0:

    for layer: CALayer in self.view.layer.sublayers! {
        layer.removeFromSuperlayer()
    }

or

    self.view.layer.performSelector("removeFromSuperlayer")
Alvin George
  • 14,148
  • 92
  • 64
2

Swift 5:

You can either remove the layer itself or iterate through them and do the following:

layer.removeAllAnimations()
layer.removeFromSuperlayer()
Matias Jurfest
  • 1,378
  • 16
  • 25
1

Swift 4.1

self.view.layer.sublayers?.removeAll()

or if in a UIView sub-class just

layer.sublayers?.removeAll()

JonJ
  • 1,061
  • 6
  • 8
  • 2
    this crashes, any ideas why – mKane Sep 06 '18 at 17:09
  • There's a gotcha here - beware that you didn't create a layer that you then subsequently try to access after removing all sublayers at another place in your code! – JonJ Sep 13 '18 at 18:06
0

If you want to delete all sublayers and add a new one, you can easily do:

rootLayer.sublayers = [layer1] // adding one layer

rootLayer.sublayers = [layer1, layer2, ...] // adding two or more layers

This could be helpful, if you work with tableview or collectionview cells. You don't need to call prepareForReuse for removing the sublayers.

Sean Stayns
  • 4,082
  • 5
  • 25
  • 35