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.
Related
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"])
Is there a standard mechanism for annotating function declarations in Swift to indicate that they are present because a class conforms to some protocol?
For instance, this declaration might be present because a class conforms to NSCoding. (Marking it with override would result in a syntax error, so it's not the kind of annotation I am looking for.) Ideally I am looking for a code-level annotation (e.g. override instead of /*! ... */).
// ... annotation such as "conform to NSCoding", if possible
func encodeWithCoder(encoder: NSCoder) {
// ...
}
You can use extension. for example:
protocol SomeProtocol {
func doIt() -> Int
}
class ConcreteClass {
....
}
extension ConcreteClass: SomeProtocol {
func doIt() -> Int {
// ...
return 1
}
}
But you cannot define required initializer in extension, for example:
// THIS DOES NOT WORK!!!
class Foo: NSObject {
}
extension Foo: NSCoding {
required convenience init(coder aDecoder: NSCoder) {
self.init()
}
func encodeWithCoder(aCoder: NSCoder) {
// ...
}
}
emits an error:
error: 'required' initializer must be declared directly in class 'Foo' (not in an extension)
required convenience init(coder aDecoder: NSCoder) {
~~~~~~~~ ^
In this case, you should use // MARK: comments:
class Foo: NSObject {
// ...
// MARK: NSCoding
required init(coder aDecoder: NSCoder) {
super.init()
}
func encodeWithCoder(aCoder: NSCoder) {
// ...
}
}
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.
I'm getting some compiler errors in Xcode 6 using Swift which I have a hard time wrapping my head around. I'm trying to create a scene by subclassing SCNScene, but keep getting errors on the initialisers. The basic structure of my code is:
class SpaceScene: SCNScene {
override init(named: String) {
super.init(named: named)
}
}
This results in an error on line 2 with the message "Initializer does not override a designated initializer from its superclass", although SCNScene clearly has such an initialiser. I think i'm missing something basic - any insights?
On XCode 6.1, the following should do it:
class SpaceScene : SCNScene {
override init() {
super.init()
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
I'm attempting to create a custom NSTextFieldCell subclass in Swift (Xcode Beta 5), with the following code:
class CustomHighlightTextFieldCell : NSTextFieldCell {
required init(coder aCoder: NSCoder!) {
super.init(coder: aCoder)
}
init(imageCell anImage: NSImage!) {
super.init(imageCell: anImage)
}
init(textCell aString: String!) {
super.init(textCell: aString)
}
}
However, I receive compilation errors on the 2nd and 3rd init() declarations:
/Users/Craig/projects/.../CustomHighlightTextFieldCell:8:40: Invalid redeclaration of 'init(imageCell:)'
/Users/Craig/projects/.../CustomHighlightTextFieldCell.swift:17:5: 'init(imageCell:)' previously declared here
/Users/Craig/projects/.../CustomHighlightTextFieldCell:7:39: Invalid redeclaration of 'init(textCell:)'
/Users/Craig/projects/.../CustomHighlightTextFieldCell.swift:21:5: 'init(textCell:)' previously declared here
While there are some strange compiler bugs here (I'm getting the usual "SourceKitService Terminated, Editor functionality temporarily limited." message), it seems like I'm missing something in my method overriding - but I can't tell what.
I was under the assumption the named parameters, or at least the parameter types, would indicate that there are three different init() methods here, but apparently I'm missing a key piece of the puzzle.
Edit: If I add override to the 2nd and 3rd init() methods, I have a separate issue:
required init(coder aCoder: NSCoder!) {
super.init(coder: aCoder)
}
override init(imageCell anImage: NSImage!) {
super.init(imageCell: anImage)
}
override init(textCell aString: String!) {
super.init(textCell: aString)
}
This new issue (simply invoked by adding the two override keywords) seems to almost contradict the original.
/Users/Craig/projects/.../CustomHighlightTextFieldCell.swift:17:14: Initializer does not override a designated initializer from its superclass
/Users/Craig/projects/.../CustomHighlightTextFieldCell.swift:21:14: Initializer does not override a designated initializer from its superclass
It would seem that your declarations (with override) should be sufficient, however, they seem to need the #objc declarations as well. This works:
class CustomHighlightTextFieldCell : NSTextFieldCell {
required init(coder aCoder: NSCoder!) {
super.init(coder: aCoder)
}
#objc(initImageCell:)
override init(imageCell anImage: NSImage!) {
super.init(imageCell: anImage)
}
#objc(initTextCell:)
override init(textCell aString: String!) {
super.init(textCell: aString)
}
}
As you see, you have the corresponding super.init(xxx) in the functions which means you are overriding the functions. So just add the override keyword.
override init(imageCell anImage: NSImage!) {
super.init(imageCell: anImage)
}
override init(textCell aString: String!) {
super.init(textCell: aString)
}