Overridden properties issue in Swift - swift

I have a subclass of UIButton as follows:
class VectorizedButton: UIButton {
override var highlighted: Bool {
didSet {
setNeedsDisplay()
}
}
}
Everything works great, until I added this line in my root controller:
var twitterButton: TwitterButton?
TwitterButton extends VectorizedButton.
Here is the error I get:
...UIView+Vectorized.swift:42:7: Class 'VectorizedButton' has no initializers
...UIView+Vectorized.swift:44:18: Stored property 'highlighted' without initial value prevents synthesized initializers
Easy, let's set a default value:
override var highlighted: Bool = false
Tougher error:
<unknown>:0: error: super.init called multiple times in initializer
<unknown>:0: error: super.init called multiple times in initializer
<unknown>:0: error: super.init called multiple times in initializer
Try overriding init?
required init(coder aDecoder: NSCoder) {
highlighted = false
super.init(coder: aDecoder)
}
Even more errors:
error: 'self' used before super.init call
highlighted = false
^
error: 'self' used before super.init call
highlighted = false
^
Anyone cares to explain what's going on here?

You just had to add the required init
Here is what I did :
class VectorizedButton: UIButton {
override var highlighted: Bool {
didSet {
setNeedsDisplay()
}
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
class TwitterButton: VectorizedButton {
}
And in a ViewController :
var twitterButton: TwitterButton?
Works fine like this.
You wanted to override the highlighted property and create the twitterButton as Optional, so you need to implement an init in your class.
You cannot set the highlighted property with this :
override var highlighted: Bool = false
You need to set it in the init, or like this :
override var highlighted: Bool {
get { return false }
set { super.highlighted = newValue }
}
And for this :
required init(coder aDecoder: NSCoder) {
highlighted = false
super.init(coder: aDecoder)
}
You need to set your property after the call to super.init.

Related

Swift UIView subclass init failing

I created a UIView subclass:
class RA_Circle: UIView {
let elipseWidth:CGFloat
let elipseHeight:CGFloat
init(elipseWidth: CGFloat, elipseHeight:CGFloat) {
self.elipseWidth = elipseWidth
self.elipseHeight = elipseHeight
super.init(frame: CGRect.zero)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
But the compiler is giving me this error on the required init:
Property 'self.elipseWidth' not initialized at super.init call
I was following this SO Q&A:
How to properly init passed property in subclass of UIView?
In your class definition you're declaring your variable without any default values, and the required initializer is not providing any values before calling super init.
There are a number of ways to deal with this, here's a few...
One way is to provide default values in the property declarations:
var elipseWidth: CGFloat = 0.0
var elipseHeight: CGFloat = 0.0
The second is to make your properties optional:
var elipseWidth: CGFloat?
var elipseHeight: CGFloat?
A third is to provide default values in the required initializer:
required init?(coder aDecoder: NSCoder) {
elipseWidth = 14.0
elipseHeight = 14.0
super.init(coder: aDecoder)
}
You have to change the let variable declarations to var and optional. In this case, you would initialize them in awakeFromNib() or at some later time.

How can I subclass UISegmentedControl having custom designated initializer?

Seems like a trivial issue but I am not able to make this compile.
Neither in playgrounds nor in normal swift ios projects.
(Please note I am not using Storyboards that's why I don't need / care about the init?(coder) part..it;s jsut it has to be include otherwise the complier complains about it.)
class SegmentedControl: UISegmentedControl {
let configuration: [String]
required init(configuration: [String]) {
self.configuration = configuration
super.init(items: configuration)
}
required init?(coder aDecoder: NSCoder) { fatalError() }
}
let x = SegmentedControl(configuration: ["a","b"])
It is complaining about not having the deisignated initializer implemented.
Fatal error: Use of unimplemented initializer 'init(frame:)' for class
'__lldb_expr_167.SegmentedControl'
I don't understand what is going on here. Isn't the designated initializer the init(items:) for UISegmentedControl? I am calling it in my subclass designated initializer.
Solution:
class SegmentedControl: UISegmentedControl {
var configuration = [String]()
required init(configuration: [String]) {
super.init(items: configuration)
self.configuration = configuration
}
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) { fatalError() }
}
let x = SegmentedControl(configuration: ["a","b"])

Swift: How to add new property to UIImageView class?

I'm afraid I'm relatively new to Swift, but have looked around as best I could and haven't been able to figure out how to do this relatively simple task!
I would like to add a new property called "angle" to the class UIImageView, such that you could use "image.angle". Here's what I've got, having attempted to follow the method of a tutorial I used (note that the required init? part was suggested by Xcode and I am not too sure of what it does):
class selection_image: UIImageView {
var angle = Double()
init(angle: Double) {
self.angle = angle
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Thank you very much for any help!!
class selection_image: UIImageView {
var angle = Double()
// your new Init
required convenience init(angle: Double) {
self.init(frame: CGRect.zero)
self.angle = angle
}
override init(frame: CGRect) {
super.init(frame: CGRect.zero)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Using Swift 4.2
#jasperthedog. You can add a property to a given class using AssociatedObjects of the Runtime using an extension as follows:
In this example, I add an optional viewAlreadyAppeared: Bool? property to UIViewController. And with this, I avoid creating subclasses of UIViewController
extension UIViewController {
private struct CustomProperties {
static var viewAlreadyAppeared: Bool? = nil
}
var viewAlreadyAppeared: Bool? {
get {
return objc_getAssociatedObject(self, &CustomProperties.viewAlreadyAppeared) as? Bool
}
set {
if let unwrappedValue = newValue {
objc_setAssociatedObject(self, &CustomProperties.viewAlreadyAppeared, unwrappedValue as Bool?, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}
}

Swift 1.2: 'self' used before super.init call

I have this code:
class SomeViewController : UIViewController {
let deferred : ()->()
required init(coder aDecoder : NSCoder) {
deferred = {
self.doSomething()
}
super.init(coder: aDecoder)
}
func doSomething() {
// Does things....
}
}
In Swift 1.2 this fails to compile with the error:
'self' used before super.init call
In pre-1.2 days, we can address this in a number of ways such as implicitly unwrapped conditionals. That approach won't work any longer.
I've seen other answers reference 2-stage initialization or the lazy decorator, but both sacrifice immutability of the property. Surely this must be solvable in Swift 1.2, but I'm out of ideas.
Here's an interim workaround:
private(set) var deferred : ()->() = { }
required init(coder aDecoder : NSCoder) {
super.init(coder: aDecoder)
self.deferred = {
self.doSomething()
}
}
My thinking is, okay, we did "sacrifice immutability of the property", but from a public perspective the property remains immutable because the setter is private.

How to factorize Swift class initialization in order to avoid redundant code?

I am trying to do a custom UIPickerView. In my custom class, I have to override "init(coder aDecoder: NSCoder)" initializer.
In the same time I want to have an initialiser without any parameter.
According to error message, my class variables initialization is mandatory, but their initialization is not detected if done in a separate function.
class MyPickerView: UIPickerView{
var maxInt:CInt;
func baseInit(){
maxInt = 10;
}
override init() {
maxInt = 10;
super.init();
}
required init(coder aDecoder: NSCoder) {
maxInt = 10;
super.init(coder: aDecoder)
}
}
There, I do have redundant code for my "maxInt" initialization.
If I replace the intialization of maxInt in the initializer, I have this error message:
Property 'self.maxInt' not initialized at super.init call
What should I do. What should the best practice?
Thank you for your help.
You can make the var optional or initialize in at the declaration
class MyPickerView: UIPickerView {
var maxInt:CInt = 10 // or var maxInt:CInt?
}
or
class MyPickerView: UIPickerView {
var maxInt:CInt?
func setup() {
maxInt = 10
}
}