1

I need UIButton to have the property bookId. I tried the following code but it's giving me the error Property 'self.bookId' not initialized at super.init call. I need the property to be able to query the database for that specific bookId when the button is clicked on.

import UIKit

class BookUIButton: UIButton {
var bookId: String

init(frame: CGRect, bookId: String) {
    super.init(frame: frame);
    self.bookId = bookId
}

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

override init(frame: CGRect) {
    super.init(frame: frame)
}

override func awakeFromNib() {
    super.awakeFromNib()

    //TODO: Code for our button
}
}

Any help would be greatly appreciated!!!

Mohit Kumar
  • 2,898
  • 3
  • 21
  • 34
Rue Vitale
  • 1,549
  • 4
  • 17
  • 24
  • 1
    Get rid of the `init(frame:)` implementation and give `bookId` a default value in `init(coder:)`. Generally, that error tells you that you must initialize your properties in every initializer you have. – Eilon Jan 31 '20 at 17:56
  • I believe this is answered in another StackOverflow article: [Here](https://stackoverflow.com/questions/24021093/error-in-swift-class-property-not-initialized-at-super-init-call) – Su Llewellyn Jan 31 '20 at 18:42

3 Answers3

1

swift enforces you to initialize every member var before it is ever/might ever be used. Since it can't be sure what happens when it is supers turn, it errors out: better safe than sorry!

Solution 1:

class BookUIButton: UIButton {
var bookId: String?

init(frame: CGRect, bookId: String) {
    super.init(frame: frame);
    self.bookId = bookId
}

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

override init(frame: CGRect) {
    super.init(frame: frame)
}

override func awakeFromNib() {
    super.awakeFromNib()

    //TODO: Code for our button
}
}

Solution 2: There is a better way to skip this error. So all you have to do is to initialize member after declaration:

class BookUIButton: UIButton {
var bookId: String = String()

init(frame: CGRect, bookId: String) {
    super.init(frame: frame);
    self.bookId = bookId
}

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

override init(frame: CGRect) {
    super.init(frame: frame)
}

override func awakeFromNib() {
    super.awakeFromNib()

    //TODO: Code for our button
}
}
Mohit Kumar
  • 2,898
  • 3
  • 21
  • 34
0

Is it important to have it named bookId? And is it important to be a string? What if you just gave the UIButton a tag? (e.g. ButtonName.tag = Int)

0

Since you can always instantiate a button from storyboard, that button need to have a required init?(coder aDecoder: NSCoder). That method is required just for you to insert a button in the storyboard. If the button is actually created via storyboard, than of course it won't have the id soon enough (at init time) for it not to be optional.

Since I assume that you will always instantiate the button programmatically, and not via storyboard, you can just implement your own init, with your params, and than, in the required init, just insert a fatalError.

That will compile as the fatalError returns Never (meaning it never returns), so the compiler can understand that bookId will never actually be nil.

Actually if you delete the required init Xcode will suggest you to insert the method with a fatalError and will autocomplete it for you if you want.

Of course, after that, if you put a button of this class in the storyboard, it will crash, so don't do that.

Adding a property to a button (or view in general) and force it to be created via some init and not via storyboard, in general, is perfectly fine if you don't intend to use the storyboard for that button (or view).

PS: after this brief on how to do what you want to do, I want to suggest you NOT to do it in THIS case, as it seems a bad idea for a button to hold any sort of data about some API you need to call. The button should just be a button and inform you when the user taps it. Then, when the button is pressed, some other class should handle what to do, using some other model to get the correspondent bookId for that button tap.

Completely different was if you would add some property that helped the button to look different, or add some other behavior specific to the use of the button (which is just be tappable and inform of taps)

Enricoza
  • 1,101
  • 6
  • 18