I have a simple swift class:
class School: NSObject {
var myData: NSData
var timestamp: NSDate
var id: Int
override init() {
//ERROR: Property 'self.myData' not initialized at super.init call
super.init()
}
}
Why I get the compiler error mentioned above?
All properties must be initialized before you chain up to a super initializer. Otherwise you would end up with uninitialized memory, which is not allowed in Swift. Therefore, you must set myData, timestamp, and id or make them optional.
Related
I'm trying to access a singleton value that is accessible throughout my application apart from one function. I can get the value at either end of the function however inside the function it can't be accessed. To confirm I have set these values so they are not empty.
My singleton is declared as follows:
var customer: Customer = Customer.sharedInstance
final class Customer {
static let sharedInstance = Customer()
var name: String!
var address: String!
var zipcode: String!
var id: String!
private init() {}
}
I can access any of these values from within viewDidLoad and other methods apart from one which is below:
fileprivate func processCustomer() {
... Do logic here
print(customer.name) // Print's out nil
... perform closure method
... print(customer.name) // Print's nil
}
Any ideas as I've rewritten it twice already. I've also removed fileprivate and renaming the function. It's almost as if the function can't read the value of a singleton more than once??
Thanks
I have a custom class which I want to initialise from a JSON object using JSONCodable https://github.com/matthewcheok/JSONCodable
So I have
public var id: String
public var name: String?
public var imageURL: NSURL?
and a failable initialiser which conforms to the JSONCodable protocol
required public init?(JSONDictionary: JSONObject) {
let decoder = JSONDecoder(object: JSONDictionary)
do {
id = try decoder.decode("id")
name = try decoder.decode("name")
if let imageURLString: String = try decoder.decode("image") {
imageURL = NSURL(string: imageURLString)
}
}
catch let error as NSError{
NSLog("\(error.localizedDescription)")
return nil
}
}
I am getting a compiler error on the 'Return nil' statement:
All stored properties of a class instance must be initialized before returning nil from an initialiser.
Is there a way round this, apart from setting dummy values? One of the properties I want to include is read-only, I really don't want to create a setter just to get round the compiler.
I am using a class, not a struct as in the JSONCodable sample code, because I want to subclass.
One possibility is to have a non failing initialiser which throws an error, but this wouldn't conform to the JSONCodable protocol.
I'm fairly new to Swift, any pointers on how to handle this would be very welcome.
Fixed with the help of this answer: Best practice to implement a failable initializer in Swift (mentioned here https://github.com/matthewcheok/JSONCodable/issues/5)
So now I have
public var id: String!
id is now implicitly unwrapped so it has a default value of nil.
I'm writing a singleton class to access socket by adopting socket.IO-objc, here's what I did so far:
class Singleton_SocketManager: NSObject, SocketIODelegate {
var isSocketConnected: Bool = false
var socket: SocketIO
override init() {
super.init()
}
class var sharedInstance: Singleton_SocketManager {
struct Static {
static var onceToken: dispatch_once_t = 0
static var instance: Singleton_SocketManager? = nil
}
dispatch_once(&Static.onceToken) {
Static.instance = Singleton_SocketManager()
}
return Static.instance!
}
}
Yet the compiler complains:
Property 'self.socket' not initialized at super.init call
How should I write my init method here to make the compilation error go away?
By the way, I transitioned the code above from objective-c, in obj-c, the SocketIO is initialized like so:
self.socket = [[SocketIO alloc] initWithDelegate:self];
And If I put the init method this way:
override init() {
self.socket = SocketIO(delegate: self)
super.init()
}
It complains:
self used before super.init call
Is it necessary to inherit from NSObject for your application? I ran into a similar situation where I needed to set the Singleton as a delegate (so I needed self). By not inheriting from NSObject, my issue was resolved - no need to call super.init() anyway then
Apple's recommendation for a Singleton is like this :
If you need to perform additional setup beyond initialization, you can assign the result of the invocation of a closure to the global constant:
class Singleton {
static let sharedInstance: Singleton = {
let instance = Singleton()
// setup code
return instance
}()
}
But a (I think) more recent syntax can also be found on their swift blog, which I prefer :
class Singleton {
static let sharedInstance = Singleton()
private init() {
// do your init here
print("Singleton created")
}
}
You can follow the below option as suggested in the below url
Error in Swift class: Property not initialized at super.init call - How to initialize properties which need use of self in their initializer parameter
var socket: SocketIO!
Quote from The Swift Programming Language, which answers your question:
“Swift’s compiler performs four helpful safety-checks to make sure
that two-phase initialization is completed without error:”
Safety check 1 “A designated initializer must ensure that all of the
“properties introduced by its class are initialized before it
delegates up to a superclass initializer.”
Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks.
https://itunes.apple.com/us/book/swift-programming-language/id881256329?mt=11
Credits: Ruben on this question
Another solution is to make the 'socket' variable unwrapped optional.
var socket:IOSocket!
I'm trying to convert the following Objective-C code to Swift. In my Objective-C code, there's a static variable and its accessed from a class method.
#implementation SomeClass
static NSMutableArray *_items;
+ (void)someMethod {
[_items removeAll];
}
#end
Since you can't access types declared like this private var items = [AnyObject]() from class functions in Swift, I created a stored property for it like this.
class var items: [AnyObject] {
return [AnyObject]()
}
And I'm trying to call a method on it from a class function like so.
class func someFunction() {
items.removeAll(keepCapacity: false)
}
But I get this error Immutable value of type '[AnyObject]' only has mutating members named 'removeAll'.
Can anyone please tell me what's the cause of this error and how to correct it?
Thank you.
With this code:
class var items: [AnyObject] {
return [AnyObject]()
}
you are not creating a stored property - instead it's a computed property, and the worst part is that every time you access to it, a new instance of [AnyObject] is created, so whatever you add to it, it's lost as soon as its reference goes out of scope.
As for the error, the static computed property returns an immutable copy of the array that you create in its body, so you cannot use any of the array method declared as mutating - and removeAll is one of them. The reason why it is immutable is because you have defined a getter, but not a setter.
Currently Swift classes don't support static properties, but structs do - the workaround I often use is to define an inner struct:
class SomeClass {
struct Static {
static var items = [AnyObject]()
}
}
SomeClass.Static.items.append("test")
If you want to get rid of the Static struct every time you refer to the items property, just define a wrapper computed property:
class var items: [AnyObject] {
get { return Static.items }
set { Static.items = newValue }
}
so that the property can be accessed more simply as:
SomeClass.items.append("test")
Updated to Swift1.2
In Swift1.2[Xcode6.3], you can declare static properties using keyword static, also you can declare static methods using keyword class or static.
class SomeClass {
// use static modifier to declare static properties.
static var items: [AnyObject]!
// use class modifier to declare static methods.
class func classMethod() {
items.removeAll(keepCapacity: false)
}
// use static modifier to declare static methods.
static func staticMethod() {
items.removeAll(keepCapacity: false)
}
}
EDIT:
The difference between static and class modifier is that static is just an alias for "class final",so methods modified with static can not be overridden in subclasses.
Thanks #Maiaux's
Yet the manual for Swift 2 still claims just enumeration ond structures may use static store properities.
I'm using XLForm, which has a class XLFormDescriptor, which needs to be initialized with init(title: String).
The title I want to use is the return value of my current class's name function (class-level properties aren't a feature yet).
Putting this at a class level, the code to set it up looks like this:
let settingsForm = XLFormDescriptor(title: self.name())
But this gives the error:
'PanelController -> () -> PanelController!' does not have a member
named 'name'
Putting this at the top of the class's init call looks like this:
let settingsForm: XLFormDescriptor
override init() {
self.settingsForm = XLFormDescriptor(title: self.dynamicType.name())
super.init()
}
And doing that gives this error:
'self' used before super.init call
Putting it after super.init() gives this error:
Property 'settingsForm' not initialized at super.init call
Any ideas how I can possibly do this?
EDIT: A workaround is to do this:
let settingsForm = XLFormDescriptor(title: "")
override init() {
super.init()
self.settingsForm = XLFormDescriptor(title: self.dynamicType.name())
}
In swift, self is not available until all class properties have been initialized. There's a check at compilation time for that.
So if you have a class with properties, inherited from another class:
class A {
var prop1: Int
init(val1: Int) {
self.prop1 = val1
}
}
class B : A {
var prop2: String
override int(val1: Int, val2: String) {
// First initialize properties of this class
self.prop2 = val2
// Next call a superclass initializer
super.init(val1: val1)
// From now on, you can use 'self'
}
}
you cannot use self until all (non optional) class properties have been been initialized and a superclass initializer has been invoked (if the class is inherited).
If you initialize a property inline, like this:
let settingsForm = XLFormDescriptor(title: self.name())
you are explicitly using self before the class instance has been properly initialized - that's the reason of the compilation error.
The solution you found yourself is not a workaround, but the right way of doing it. You first initialize the property with a value not referencing self, then once the class has been initialized, you assign that property a new value.
Note that this is the only case where you are allowed to assign a new value to an immutable property, as long as it is done from within an initializer.
For a better understanding of how initialization works, I recommend reading the corresponding documentation: Initialization