1

I am trying to subclass NSTextView and have a custom initializer.

When I add a custom initializer like below:

init(frame: NSRect, view: NSView) {
        
    self.view = view
    self.textLayer = CATextLayer()
        
    super.init(frame: frame)
}

the compiler complains about missing init?(coder: NSCoder) initializer and suggests the below as a fix:

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

When I apply this fix, the code compiles fine but when I run it, the app crashes giving me Fatal error: Use of unimplemented initializer 'init(frame:textContainer:) error in the logs.

I looked at other solutions on SOF and they suggested the below:

required init?(coder: NSCoder) {
    super.init(coder: coder)
}

Unfortunately, the above also doesn't fix the issue and I am getting the same crash error as before.

Any ideas what I may be doing wrong? I am using Swift 5.0. Additionally, I know there are other similar questions on SOF but their answers didn't solve my problem (maybe because of Swift's version).

Do note that removing the custom init will fix the issue but I would like to keep the custom initializer in this case.

P.S. Swift noob here so apologies if its something trivial.

Ram Patra
  • 16,266
  • 13
  • 66
  • 81
  • What does the custom `init` look like? – Phillip Mills Jun 27 '20 at 18:53
  • @PhillipMills updated the question with my custom `init` – Ram Patra Jun 27 '20 at 18:59
  • Please show your real code, don't just describe it. We need to be able to copy and paste right into a project and just go. Don't make us write the code you already wrote. Thanks. – matt Jun 27 '20 at 19:04
  • @matt I have pasted all the necessary code in the question. It's a normal class extending `NSTextView` and has one custom `init` as mentioned in the question. There's nothing else yet in the class. – Ram Patra Jun 27 '20 at 19:08
  • Yes, but then I still have to write `class MyTextView: NSTextView` etc. Do you see? There's nothing else in the class but you didn't even _provide_ the class. So I have no way of knowing if I'm doing what you did, and you are making me do the work. – matt Jun 27 '20 at 19:09

2 Answers2

3

Your subclass needs to call the designated initializer of the parent. Change super.init(frame: frame) to super.init(frame: frame, textContainer: nil).

Phillip Mills
  • 30,888
  • 4
  • 42
  • 57
2

The problem is that writing a new designated initializer blocks inheritance, so the real designated initializer, init(frame:textContainer:), can no longer be called.

You need to make your initializer a convenience initializer to prevent that from happening. And then you won't be forced to write init(coder:) either and all will be well.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • And please read my https://stackoverflow.com/a/30719434/341994 — basically, this is an unwitting duplicate of that question, as the whole phenomenon, you will see, is identical. – matt Jun 27 '20 at 19:11
  • 1
    When I add `convenience` to `init`, it says, Convenience initializer must delegate (with 'self.init') rather than chaining to a superclass initializer (with 'super.init'). However, the other answer solved my problem. – Ram Patra Jun 27 '20 at 19:22
  • Also, how does my custom `init` block inheritance? And, how is `init(frame:textContainer:)` the designated initializer? – Ram Patra Jun 27 '20 at 19:33
  • That's right, you'd have to rewrite. But you can do that. I'm not going to bother to show you the rewrite. Your other questions are just factual, I'm not going to repeat myself. – matt Jun 27 '20 at 19:43