When is "required init?(coder aDecoder: NSCoder)" called on a UIView or UIViewController?
Asked Answered
T

2

25

When I create a subclass of UIView or UIViewController with a stored property, Xcode will not compile my project unless I include an implementation of required init?(coder aDecoder: NSCoder). Currently, I have the following implementation to shut the compiler up:

required init?(coder aDecoder: NSCoder) {
    fatalError()
}

I understand why I'm required to include this initializer; my subclass needs to conform to the NSCoding protocol because its superclass conforms to it, and this initializer is part of the NSCoding protocol so it needs to work with my class, i.e. initialize all of my class's stored properties (which the superclass version of the initializer won't do).

I imagine that a correct implementation would look something like this:

class MyView: UIView {
    let label: UILabel

    override init(frame: CGRect) {
        label = UILabel()
        super.init(frame: frame)
    }

    required init?(coder aDecoder: NSCoder) {
        if let label = aDecoder.decodeObject() as? UILabel {
            self.label = label
        } else {
            return nil
        }
        super.init(coder: aDecoder)
    }

    override func encode(with aCoder: NSCoder) {
        aCoder.encode(label)
        super.encode(with: aCoder)
    }
}

However, considering that my application has over 50 custom views and view controllers, correctly implementing this function in every custom view and view controller is a lot of work.

So, I'm wondering if it's necessary to implement this initializer correctly, or if I can just leave it throwing a fatal error. In other words, will this initializer ever be called if I don't call it in my own code? I think I read that it might be called by a Storyboard, but my app doesn't use any Storyboards.

Tubulate answered 8/9, 2018 at 21:28 Comment(2)
This initialiser will be called if an instance of your view is used in a storyboard scene or xib file.Maisel
@Paulw11, you should post that as the answer.Helsie
M
21

This initialiser will be called if an instance of your view is used in a storyboard scene.

It is up to you whether to create a functioning initialiser or not, but it should mostly be a matter of copying code from init(frame:)

Maisel answered 8/9, 2018 at 21:37 Comment(5)
Ok. As a follow-up to this, if I choose not to make a functioning initializer, is there a better way to mark this than just throwing a fatal error? I.e. a way to mark it that will cause a compiler error if someone tries to call it from code, instead of a runtime error?Tubulate
No, you can call fatal error or you can return nil since it is a failable initialiser.Maisel
Isn't the NSCoder one only used with storyboards? I never seen using it with xibs.Impenitent
A storyboard is basically just a bunch of Xibs with some additional information; when used in the app, there's not much difference.Resultant
To answer my follow-up question above, there is now a way to mark this initializer so that it will cause a compiler error. Just declare it with unavailable: @available(*, unavailable) required init?(coder: NSCoder)Tubulate
S
3

It provides an NSCoder instance as a parameter, which you need only if you are using iOS serialization APIs. This is not used often, so you can ignore it. If you are curious to learn, serialisation converts an object in a byte stream that you can save on disk or send over the network.

During the initalization of a view controller, you usually allocate the resources that the view controller will need during its lifetime. So, this include model objects or other auxiliary controllers, like network controllers.

enter image description here

Shechem answered 13/9, 2022 at 13:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.