Swift UIView subclass init failing - swift

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.

Related

UIHostingController throws

I want to load from a UIViewController a SwiftUI based view that reads a json local to the bundle. The code and binding in a swiftUI only project works fine, when I leverage the UIHostingController I get an error for which I am seeking help to fix.
class ProgramsListVCHost : UIHostingController<ProgramsList>, Storyboarded {
weak var coordinator: MainCoordinator?
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder, rootView: ProgramsList())
}
}
The code above crashes because I didn't pass what I should have to cause the init of the model.
super.init(coder: aDecoder, rootView: ProgramsList().environmentObject(ProgramUserData()))
However, if I do that the compiler demands that I cast the whole thing to the underlying class ProgramList (Cannot convert value of type 'some View' to expected argument type 'ProgramsList')
If I do apply the recommended fix, the code crashes with the error:
Could not cast value of type
'SwiftUI.ModifiedContent>>'
(0x7fff89d0ec68) to 'bikeit.ProgramsList' (0x110477328). 2019-11-15
14:36:26.049041-0500 bikeit[13658:8386085] Could not cast value of
type 'SwiftUI.ModifiedContent>>'
(0x7fff89d0ec68) to 'bikeit.ProgramsList' (0x110477328). (lldb)
I don't understand how to initialize the object that I must pass in order to make it work.
Of course, it is because your declared content UIHostingController<ProgramsList> is ProgramsList, so it is expected in initialiser, but you pass to it output of .environmentObject, which is SwiftUI.ModifiedContent, so types checking fails and you get compiler error.
It is not clear your needs, but possible solution could be as follows:
class ProgramsListVCHost : UIHostingController<AnyView>, Storyboarded {
weak var coordinator: MainCoordinator?
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder, rootView: AnyView(ProgramsList().environmentObject(ProgramUserData())))
}
}
Update: found alternate
class ProgramsListVCHost : UIHostingController<ProgramsListVCHost.MyView>, Storyboarded {
// Internal view
struct MyView: View {
var body: some View {
ProgramsList().environmentObject(ProgramUserData())
}
}
weak var coordinator: MainCoordinator?
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder, rootView: MyView())
}
}

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)
}
}
}
}

Instantiate class with NSCODER

I face a problem when trying to instantiate a class(SettingsView) that uses NSCoder, in another class(Swipe). The SettingsView class is already an instance of an objective -C class(FXBlurView)
I get the following error "Missing argument for parameter 'coder' in call". I realized that I have to call some parameters, but I do not know which.
SettingsView :
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
self.tintColor = UIColor.clearColor()
}
Swipe :
var settings = SettingsView()//error occurs here
i already tried to use
init () {
super.init (tint: ...)
}
But it seems to be not functionnal.
Ok , i succeed to do it just by adding :
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
var settings = SettingsView(coder: aDecoder)
}
into my "Swipe" view controller.

Overridden properties issue in 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.