3

I'm trying to set a CALayer's delegate so that I can use draw(_:in:). The documentation describes how to do it. But as soon as I set the delegate, there's a runtime error:

Thread 1: EXC_BAD_ACCESS (code=EXC_I386_GPFLT)

Here's code that generates an error. Replace ViewController.swift in the Single View Application template in Xcode 8.2.1:

import UIKit
class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        let myLayer = CALayer()
        myLayer.delegate = LayerDelegate()
        view.layer.addSublayer(myLayer)
    }
}

class LayerDelegate: NSObject, CALayerDelegate {
}
Robert
  • 6,660
  • 5
  • 39
  • 62
  • 2
    `CALayer`'s `delegate` property is `weak`, so setting a new object like that to it is going to cause it to deallocate immediately. Not sure if that's the source of your exception, though... – Robert Jan 24 '17 at 13:00
  • according to this answer : http://stackoverflow.com/a/19652248/1179863 EXC_I386_GPFLT is surely referring to "General Protection fault", which is the x86's way to tell you that "you did something that you are not allowed to do". It typically DOESN'T mean that you access out of memory bounds, but it could be that your code is going out of bounds and causing bad code/data to be used in a way that makes for an protection violation of some sort. – Ali Abbas Jan 24 '17 at 13:04
  • 1
    Did you try `class ViewController: UIViewController { let layerDelegate = LayerDelegate() override func viewDidLoad() { ... myLayer.delegate = layerDelegate }}`? – Yannick Jan 24 '17 at 13:27
  • 1
    The documentation example has the delegate saved into a strong reference within a property. Maybe this is a prerequisite, and the `weak` reference is actually an `unowned` one, thus you get a crash because the delegate gets deallocated. – Cristik Jan 24 '17 at 14:07
  • 1
    @Yannick That worked. Thanks! I made it an answer but if you create your own, I'll accept yours instead. – Robert Jan 25 '17 at 12:45
  • @Cristik That explanation makes sense, and adding a strong reference fixes the problem. Thanks! – Robert Jan 25 '17 at 12:46
  • @Robert Adding a strong reference does indeed stop the exception, so that was it. Thanks! – Robert Jan 25 '17 at 12:47

1 Answers1

2

The object is removed from memory because there is no strong reference to it. As the other @Robert pointed out, CALayer's delegate is weak and once you leave the scope, which is the viewDidLoad() function, the object is removed from memory.

You need to make sure that it is not deallocated. You can add a property to your class. This will live as long as the class lives.

class ViewController: UIViewController {
    let layerDelegate = LayerDelegate()
    override func viewDidLoad() {
        super.viewDidLoad()
        let myLayer = CALayer()
        myLayer.delegate = layerDelegate
        view.layer.addSublayer(myLayer)
    }
}
Yannick
  • 3,210
  • 1
  • 21
  • 30