Initialize UIButton with parameters - ios

I want to initialize a subclass of UIButton with parameters, however I am getting a EXC_BAD_INSTRUCTION error in my init(create: ; coder:) method:
class DayButton: UIButton {
var forCreateView: Bool
init(create: Bool? = false, coder: NSCoder? = nil){
self.forCreateView = create!
super.init(coder: coder!) //EXC_BAD_INSTRUCTION
}
convenience required init(coder aDecoder: NSCoder) {
self.init(create: Bool(), coder: aDecoder) //most definitely not right
}
}

In Swift its "better" to try to bypass custom subclass initiation as good as possible <- my opinion don't listen to it... :-)
For guys that anyway love it... You could create a convenience initializer, init your stuff here and call a designated initializer, to init the superclass also... below is an example...
class DayButton: UIButton {
var forCreateView: Bool = false
convenience init (forCreateView: Bool) {
self.init()
self.forCreateView = forCreateView
}
}
let myButton: UIButton = DayButton(forCreateView: false) //Usage

Related

Subclass of UIButton cant call the buttonType initializer

I am trying to subclass a UIButton so that its default initilizer sets it up the same way it would if you called UIButton(type: UIButtonType.roundedRect). However, I am unable to due to some Swift restrictions saying that that is not a designated initilizer. Additionally the buttonType property is read only.
How can I do this in Swift?
For reference this code does not compile because I do not call a designated initializer.
class ToggleButton : UIButton {
init() {
super.init(type: UIButtonType.roundedRect)
}
required init?(coder aDecoder: NSCoder) {
fatalError("TROUBLE")
}
}
Swift can be a little annoying with the initializers. This should do it for you.
class ToggleButton : UIButton {
convenience init() {
self.init(type: .roundedRect)
}
convenience init(type buttonType: UIButtonType) {
self.init(type: buttonType)
}
required init?(coder aDecoder: NSCoder) {
fatalError("TROUBLE")
}
}
EDIT: Feb 12, 21
As of Swift 5, this can be accomplished with the following.
class ToggleButton: UIButton {
convenience init() {
self.init(type: .roundedRect)
}
}

How to properly init passed property in subclass of UIView?

I have a subclass of UIView that I would like to pass a property to. As much as I've tried, I don't truly understand all elements of initializing.
Here is a simplified version of my code:
class inputWithIncrementView : UIView, UITextFieldDelegate {
var inputName : String // This is the property I want to receive and init
override init (frame : CGRect) {
super.init(frame : frame)
// [this is where i will use the inputName property passed on initialization]
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
// [other functions and stuff working fine here]
}
I have tried a number of things, but I'm getting confused between the UIView initializer and the way I normally initialize a non-subclassed class.
How do I modify this code to receive the string property, initialize it? Thanks
If you want to initialize a UIView with a custom property you must reconfigure its initializer:
class InputWithIncrementView: UIView {
let inputName: String
init(inputName: String) {
self.inputName = inputName
super.init(frame: .zero)
}
required init?(coder aDecoder: NSCoder) {
return nil
}
}

suclassing a UIButton of type .system

I am trying to subclass UIButton, but i want it to be of type .system. I am struggling with initializers
class FormButton: UIButton {
var type FormButtonType: FormButtomType.oneSelection
init(oftype formType: FormButtomType) {
self.type = formType
super.init(type: .system)
}
}
problem is that I have the following error message : "Must call a designated initializer of the superclass 'UIButton'
You can't override a convenience method and call super convenience method...
As an alternative you can do a static method that return a FormButton of UIButtonType.system type.
class FormButton: UIButton {
class func newButton() -> FormButton {
return FormButton.init(type: .system)
}
}
Use it like this
let button = FormButton.newButton()
I'm guessing that you need the System type because of the highlighted animation behaviour.
If so, You can override the Highlighted property in your UIButton subclass like so:
var isHighlighted: Bool {
didSet {
// If you have images in your button, add them here same as the code below
(self.isHighlighted && self.titleLabel != nil) ? (self.titleLabel!.alpha = 0.2) : (self.titleLabel!.alpha = 1.0)
}
}
The error is little bit confusing
Must call a designated initializer of the superclass 'UIButton'
but what it is trying to say is that you need to call designated initialiser before using self. So shift self.type call after super.init call. You have created a convenience initialiser which doesn't require call to super, you need to call self.
First of all, this line is syntactically wrong.
var type FormButtonType: FormButtomType.oneSelection
should be be
var type: FormButtonType = FormButtomType.oneSelection
Now you can subclass it easily.
import UIKit
class FormButton: UIButton {
var type: FormButtonType = FormButtomType.oneSelection
// convenence initializer, simply call self if you have
// initialized type
convenience init(type: UIButtonType) {
self.init(type: type)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Now if you want to initialise some property which doesn't have default or optional value then you will need to override the designated initialiser.
For Example,
class FormButton: UIButton {
var type: UIButtonType = UIButtonType.system
var hello: String // property doesn't have initial value
// This is designated initialiser
override init(frame: CGRect) {
self.hello = "Hello"
super.init(frame: .zero)
}
convenience init(type: UIButtonType) {
self.init(type: .system)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
You need to the call superclass' designated initializer:
init(oftype formType: FormButtomType) {
super.init(frame: yourframe)
self.type = formType
}

Trouble creating an instance of ViewController

All,
I have a bar button item on my ViewController. I have set a computed property to will turn the BarButton off. I want to be able to set this from another class.
Here is my code in the view controller :
class ViewController: UIViewController {
var PayButton : Int {
didSet {
navigationItem.leftBarButtonItem = nil
}
}
required init(coder aDecoder: NSCoder)
{
self.PayButton = 0
super.init(coder: aDecoder)
}
When it try and create an instance on the view controller (so I can set the PayButton integer)
let test = ViewController()
I get an error saying
Missing Argument for parameter 'coder' in call
Any ideas ?
It is asking for the parameter 'coder', because you have it in the required init.
To use your code as it stands, you would need to initialise with:
let test = ViewController(coder: NSCoder)
There are several ways to get around this. The easiest would be to remove the required initialiser.
import UIKit
class ViewController: UIViewController {
var PayButton : Int = 0 {
didSet {
navigationItem.leftBarButtonItem = nil
}
}
}
and then implement with
let test = ViewController()
test.PayButton = 0
Because you have implemented the required initializer in ViewController class.
There are two solutions
Add a default initializer
init() {
super.init(nibName: nil, bundle:nil)
}
Remove the required initializer.
class ViewController: UIViewController {
var PayButton : Int {
didSet {
navigationItem.leftBarButtonItem = nil
}
}
init() {
self.PayButton = 0
super.init(nibName: nil, bundle:nil)
}
required init(coder aDecoder: NSCoder)
{
self.PayButton = 0
super.init(coder: aDecoder)
}
Try this:
This is the required initializer:
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
This is the super initializer:
override init(frame: CGRect) {
super.init(frame: frame)
}
This is your convenience initializer where you can pass the size the view you want to create
convenience init(view: UIView){
self.init(frame: view.frame)
}
This is your convenience initializer where the view is initialized with a value pre defined:
convenience init(){
self.init(frame: CGRectZero) //Put you predefined value here
}

Initializer does not override a designated initializer from its superclass

So I've just upgraded to Xcode 6.3 Beta 3 and a lot of error(s) are appearing relating to the following:
Initializer does not override a designated initializer from its superclass.
override init() {
super.init()
}
For example this is a UIButton class:
class CustomButton: UIButton {
var target: AnyObject!
var selector: Selector!
var action: (() -> Void)!
override init() { // Initializer does not override a designated initializer from its superclass
super.init() // Must call a designated initializer of the superclass 'UIButton'
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(frame: CGRect) {
super.init(frame: frame)
}
}
This is one of my UIViewController classes:
class CustomAlertView: UIViewController {
required init(coder aDecoder: NSCoder) {
fatalError("NSCoding not supported")
}
required override init() { // Initializer does not override a designated initializer from its superclass
super.init() // Must call a designated initializer of the superclass 'UIViewController'
}
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
}
My solution is a quick fix, but I think is easier than what Apple purposes on the the Release Notes. For more information search for 19775924 http://adcdownload.apple.com//Developer_Tools/Xcode_6.3_beta_3/Xcode_6.3_beta_3_Release_Notes.pdf here. What Apple says is that you create an Objective-C file and extend it (having to add it to the header files and all) and it's on "Known Issues in Xcode 6.3 beta 3", so I think is easy to do what I did:
This is how I fixed it for UIButton:
class CustomButton : UIButton {
init() {
super.init(frame: CGRectZero)
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
And this is one of my ViewControllers (remove public if not needed):
public class GenericViewController: UIViewController {
public init() {
super.init(nibName: nil, bundle: nil)
}
required public init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
I don't use IB so I also have UIView, because I do separate the view from the viewController (remove public if not needed):
public class GenericMenuView: UIView {
public init() {
super.init(frame: CGRectZero)
}
public required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
I need this specially in views because I have a setupViews method that I override in all subclasses that is called on the init. And using AutoLayout I don't need any frames (so I don't override the init with the frame parameter).
So it seems you have to drop override. Oh! and be sure to not call self.init() or the class is never initialized (and it crashes after some internal timeout).
As per Apple documentation here, what you are overriding is a convenience initializer. So for your initializer to work, you will have to change the method to
override convenience init() {
super.init()
}
You can either do that, or remove the initializer if you are not really using it except for calling the superclass initializer.
I recently figured this out and I'd like to explain what the problem was. Originally answered on the Apple Developer forums.
It seems Swift has changed the strategy for initializer dependency checking or for imporing initializers.
Now if your initializers' are as shown, one way to deal with both Xcode 6.3 Beta 2 and Beta 3 is to remove all initializer definitions:
class CustomButton: UIButton {
var target: AnyObject!
var selector: Selector!
var action: (() -> Void)!
}
class CustomAlertView: UIViewController {
}
Without defining any designated initializers, classes inherit all initializers of their superclasses.
A pretty easy fix, but a big gotcha that had me stumped for a while.
I think this is way easier than it seems.
For an SKSpriteNode, I was doing this:
override init() {
let texture = SKTexture(imageNamed: "bgTile")
super.init(texture: texture, color: nil, size: texture.size())
}
The problem is init() is not the designated initializer for SKSpriteNode. So I just changed it to:
override init(texture: SKTexture!, color: UIColor!, size: CGSize) {
let texture = SKTexture(imageNamed: "bgTile")
super.init(texture: texture, color: nil, size: texture.size())
}
Now it works fine.
Solution for Error : Override init(coder aDecoder: NSCoder!) not working like expected - Swift
This works for me , Try this, Note: u must awake nib
override func awakeFromNib() {
super.awakeFromNib()
// Initialisation code
}

Resources