Sunday, April 21, 2024
HomeiOS Developmentios - Why is a CALayer retained after I cease referencing it?

ios – Why is a CALayer retained after I cease referencing it?


I’ve the impression that my CALayer is retained after being added as a sublayer till the tip execution block, as a substitute of till I cease referencing it.
The father or mother UIView is nevertheless launched as quickly as it’s de-referenced as anticipated.

class DebugCALayer: CALayer {
  let id: String
  init(_ id: String) {
    self.id = id
    print("DebugCALayer init (id)")
    tremendous.init()
  }

  required init?(coder: NSCoder) { fatalError("init(coder:) has not been applied") }

  deinit { print("DebugCALayer deinit (id)") }
}

class DebugUIView: UIView {
  non-public let id: String
  init(_ id: String) {
    print("DebugUIView init (id)")
    self.id = id
    tremendous.init(body: .zero)
    layer.addSublayer(DebugCALayer(id))
  }

  required init?(coder _: NSCoder) { fatalError("init(coder:) has not been applied") }

  deinit { print("DebugUIView deinit (id)") }
}

This may be examined with this code:


remaining class CALayerReleaseTests: XCTestCase {
  override func setUp() async throws {
    print("setup")
  }

  override func tearDown() {
    print("tear down")
  }

  func testBaseline() throws {
    for i in 0..<2 {
      _ = DebugUIView("(i)")
    }
  }
}

which logs

setup
init DebugUIView 0
init DebugCALayer 0
deinit DebugUIView 0
init DebugUIView 1
init DebugCALayer 1
deinit DebugUIView 1
tear down
deinit DebugCALayer 1
deinit DebugCALayer 0

The discharge cycle for the UIView is as anticipated, with cases being de-inititalized as quickly as I’m not referencing them.
Nonetheless the CALayers stay referenced till after the check is teared-down.

If I now exit the principle thread proper after de-referencing my occasion, the reminiscence is deallocated appropriately:

  func testDispatch() throws {
    for i in 0..<2 {
      _ = DebugUIView("(i)")
      let exp = expectation(description: "")
      DispatchQueue.essential.async {
        exp.fulfill()
      }
      waitForExpectations(timeout: 1)
    }
  }

logs

setup
init DebugUIView 0
init DebugCALayer 0
deinit DebugUIView 0
deinit DebugCALayer 0
init DebugUIView 1
init DebugCALayer 1
deinit DebugUIView 1
deinit DebugCALayer 1
tear down

My guess from these observations is that calling addSublayer has a retaining facet impact on the layer that lasts till the tip of the present execution block on the principle thread. I used to be stunned to see this and was curious to grasp what is precisely taking place.

Observe: operating the identical code within the Playground offers yet one more end result…



Supply hyperlink

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

- Advertisment -
Google search engine

Most Popular

Recent Comments