I am baffled by the errors arising while trying to initialize an instance of an array in a class. The comments below are the errors xcode 6 is showing.
I have created a class. It is having instance of NSMutableArray. I want to initialize the array (hence calling self.instancename.init()). It complains if I don't. It complains if I do.
import Foundation
class testclass:NSObject {
var list_of_things:NSMutableArray;
init (){ // Designated initializer for 'testclass' cannot delegate (swith self.init);
// did you means this to be a convenience initializer?
self.list_of_things.init();
// 'init' can only refer to the initializers of 'self' or 'super'
super.init()
// Initializer cannot both delegate ('self.init') and chain to a superclass
// initializer ('super.init')
}
}
You need to assign a value to the variable, there is nothing in that variable to call init on:
init () {
self.list_of_things = NSMutableArray()
super.init()
}
Also a few notes:
You do not need semicolons at the end of lines (I know that habit is hard to break)
You do not need to inherit from NSObject
You should prefer to use native swift arrays (Array) instead of NSMutableArray
Classes should always start with capital letters
Variable names should use camel case instead of underscores
This would be my cleaned up version of your test class:
class TestClass {
var listOfThings: [AnyObject]
init () {
self.listOfThings = []
super.init()
}
}
And actually, if you just want to initialize to an empty array, you don't even need to implement init or specify the type explicitly:
class TestClass {
var listOfThings = []
}
To call the initializer of another class, you simply call it like this:
self.list_of_things = NSMutableArray()
There's no need to implicitly call the init() function, it's implied when adding the () to the class name.
You could also initialize it when you create your property, like this:
var list_of_things:NSMutableArray = NSMutableArray()
That's not how you call init on NSMutableArray.
class testclass:NSObject {
var list_of_things:NSMutableArray
init (){
self.list_of_things = NSMutableArray()
super.init()
}
}
And get rid of those semicolons! What is this? last week?
End to end answer. No superclass, using Swift arrays, init list_of_things at declaration side, in init() no superclass to initialize.
class testClass {
var list_of_things = []
init () {
}
}
126> var abc = testClass ()
abc: testClass = {
list_of_things = #"0 objects"
}
127> abc.list_of_things
$R55: __NSArrayI = #"0 objects"
Related
I am taking an online class on swift and an example was shown. Why is self used with the init method call but not on colour?
class Car {
var colour = "Black"
var numberOfSeats = 5
var typeOfCar : CarType = .Coupe
init() {
}
convenience init (customerChosenColour : String) {
self.init()
colour = customerChosenColour
}
}
An init() runs when someone makes a new instance of that class like this:
var newInstanceOfCar = Car()
A convenience init allows you to create other initializers for certain use cases, like when there is a customerChosenColour that needs to be specified. It makes things more convenient in those cases.
The reason why self is used, is because when you create convenience init, you still need to call the "main" init, which is a property of self.
You can use self on colour, but it isn't necessary. You would use self.colour, if colour was ambiguous, like in this example:
class Car {
var colour = "Black"
var numberOfSeats = 5
var typeOfCar : CarType = .Coupe
init() {
}
convenience init (colour : String) {
self.init()
self.colour = colour
}
}
Notice how colour is a property of Car, but is also the name of the parameter for the convenience init. It would be confusing to write colour = colour.
So we use self to say that we want the variable in our class, self.colour, to be equal to the value of the parameter, colour.
As you wonder why self. cannot be omitted in self.init(), you can think of self.init() as whole is a special keyword just for convenience initializer. Same as super.init() as whole is a special keyword just for designated initializer. And Car.init()aka Car() is for creating a new instance. Calling init() itself without any receiver is not a valid call ever. So you can treat function call init() as nonexistence, self.init() is one keyword, super.init() is another keyword.
init() is not a member function, it is the initializer, some special code which will be run when creating new instances of that class. Don't treat initializers as regular member functions. They don't have the func keyword in front. They don't have the property of member functions. You can call member function on an instance but you cannot call initializer on an instance (Car().init() is not valid). self.init() dose NOT mean calling a function named init() from self.
class Foo
{
init(){}
func foo(){}
func bar()
{
self.foo() //valid. regular member function call
self.init() //invalid. init() is not a member function of the instance
}
}
Don't think self.init() like calling regular method from the same class, where self. can be omitted, but rather treat the whole thing as a special keyword that means "initialize this object with the designated initializer first".
Is it possible to create a keypath referencing a method? all examples are paths to variables.
I'm trying this:
class MyClass {
init() {
let myKeypath = \MyClass.handleMainAction
...
}
func handleMainAction() {...}
}
but it does not compile saying Key path cannot refer to instance method 'handleMainAction()
KeyPaths are for properties. However, you can do effectively the same thing. Because functions are first class types in swift, you can create a reference to handleMainAction and pass it around:
//: Playground - noun: a place where people can play
import UIKit
import XCTest
import PlaygroundSupport
class MyClass {
var bar = 0
private func handleMainAction() -> Int {
bar = bar + 1
return bar
}
func getMyMainAction() -> ()->Int {
return self.handleMainAction
}
}
class AnotherClass {
func runSomeoneElsesBarFunc(passedFunction:() -> Int) {
let result = passedFunction()
print("What I got was \(result)")
}
}
let myInst = MyClass()
let anotherInst = AnotherClass()
let barFunc = myInst.getMyMainAction()
anotherInst.runSomeoneElsesBarFunc(passedFunction: barFunc)
anotherInst.runSomeoneElsesBarFunc(passedFunction: barFunc)
anotherInst.runSomeoneElsesBarFunc(passedFunction: barFunc)
This will work fine, and you can pass "barFunc" to any other class or method and it can be used.
You can use MyClass.handleMainAction as an indirect reference. It gives you a block that take the class instance as the input parameter, and returns corresponding instance method.
let ref = MyClass.handleMainAction //a block that returns the instance method
let myInstance = MyClass()
let instanceMethod = ref(myInstance)
instanceMethod() //invoke the instance method
The point is you can pass around / store the method reference just like what you did with a key path. You just need to supply the actual instance when you need to invoke the method.
In Swift 3 the dispatch_once function was removed and the migration guide suggests to use initializing closure:
let myGlobal = { … global contains initialization in a call to a closure … }()
_ = myGlobal // using myGlobal will invoke the initialization code only the first time it is used.
I'd like to access 'self' instance variables from within the initializing closure like so:
class SomeClass {
var other = SomeOtherClass()
let initialize: () = {
// self.other - this doesn't work, complains about unresolved identifier 'self'
// how to access self.other here?
} ()
func doSomething() {
// initialize will only be called once
initialize
}
}
Why is 'self' not accessible in the closure and how can make it to be?
This quoted example of the Migration Guide is misleading because it's related to a global variable.
The closure of a instance let constant is called (once) immediately when the class is initialized. That's the reason why it cannot use other variables declared on the same level.
What you can do is to initialize initialize (the variable name is not the best one ;-) ) lazily. The closure is also called only once but – as the guide describes – only the first time (when) it is used.
class SomeClass {
let other = SomeOtherClass()
lazy var initialize : () = {
let test = self.other
test.doSomething()
}()
func doSomething() {
// initialize will only be called once
_ = initialize
}
}
When an instance of the 'SomeClass' class is created, it will first create all of the variables and constants on that instance. During this time, self may not be fully initialised, because it may be halfway through setting up. Because of this, self is not available until after the initialisation step has completed.
In the example, they were talking about a global variable which has no concept of self, or a static constant on the class which also has no concept of self.
If it needs to be an instance method/variable you could:
a) make it a lazy var like
lazy var initialise : ()->Void = {
return {
// can access self here
}
}()
which will be created the first time you call it, rather than during initialisation. Of course you lose the constant that way, and you have to store the closure which is wasteful since you're only executing it once.
b) put the code inside of an init method:
init() {
// if your class doesn't have a super class, you can access self.other here.
// If it does have a super class (like NSObject) you must first call super.init() here to complete the initialisation.
// This can only be done after all other variables have been set.
}
Here is my code:
class Base
{
init(){
print("Super!")
}
}
class Test : Base
{
internal var y:Int
convenience init(_ a:Int)
{
self.init()
print("\(a)")
}
override init()
{
super.init() //Error!!! Property 'self.y' not initialized at super.init call
y = 123
}
}
I think this should be compiled:
y is not visible inside class 'Base',whether order of initializations of y's and super class's doesn't really matter.
Your argument
I think this should be compiled:
y is not visible inside class 'Base',whether order of initializations
of y's and super class's doesn't really matter.
is not correct, that would not be safe.
The superclass init can call an instance
method which is overridden in the subclass. That is (at least one)
reason why all subclass properties must be initialized before super.init() is called.
A simple example:
class Base
{
init(){
print("enter Base.init")
setup()
print("leave Base.init")
}
func setup() {
print("Base.setup called")
}
}
class Test : Base
{
internal var y:Int
override init()
{
y = 123
print("before super.init")
super.init()
print("after super.init")
}
override func setup() {
print("Test.setup called")
print("y = \(y)")
}
}
Output:
before super.init
enter Base.init
Test.setup called
y = 123
leave Base.init
after super.init
As you can see, the y property of the subclass is accessed
during the super.init() call, even if it is not known to the
superclass.
It might be interesting to compare the situation in Objective-C
where self = [super initXXX] is always called first. This has the
consequence that property access self.prop in init/dealloc methods
is unsafe and direct access to the instance variable _prop is
recommended because the object may be in a "partially constructed state".
See for example Should I refer to self.property in the init method with ARC?.
So this is one of the issues which have been solved in Swift
(at the cost of stricter requirements).
From the documentation:
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.
As mentioned above, the memory for an object is only considered fully
initialized once the initial state of all of its stored properties is
known. In order for this rule to be satisfied, a designated
initializer must make sure that all its own properties are initialized
before it hands off up the chain.
Source: Swift Language Guide: Initialization
Just exchange the two lines in init
override init()
{
y = 123
super.init()
}
I am having an issue with calling an instance method within the class itself. If someone can provide me some insight it would be greatly appreciated.
My current code looks like this:
class Rect
{
func printthis() -> String {
return "this is working or what"
}
var toPrint:String = self.printthis()
}
The error I am getting in Xcode is: Use of unresolved identifier 'self'.
What am I missing here?
You can't call an instance method without an instance. The class is merely the template for instances. So i don't what you are trying to do here...
But the answer is no, you cannot call an instance method form the class definition because there is no instance yet.
Perhaps you want to delcare a class method and use that to set an instance variable on creation? If so, you might do that like this:
class Rect {
class func printthis() -> String {
return "this is working or what"
}
var toPrint:String
init() {
toPrint = Rect.printthis()
}
}
var r = Rect()
println(r.toPrint) //-> this is working or what
An instance of a class is not initialized and able to be referenced (even as 'self') until all of its variables have been assigned values.
An option that may work for you is to declare your variable as an implicitly-unwrapped optional, which is assigned nil by default. Then in the class's init method, since all of the variables have been assigned values, you are able to start calling methods on your instance.
class Rect {
var toPrint: String!
init() {
toPrint = printthis()
}
printthis() -> String {
return "this will work"
}
}
the problem is that swift is strict about initing all properties.
you may as a workaround
class Rect
{
func printthis() -> String {
return "this is working or what"
}
var toPrint:String = ""
init() {
toPrint = printthis()
}
}