Calling Instance Method During Initialization in Swift

Call methods from Swift initializer

declare it as an implicitly unwrapped optional

class MyClass : NSObject {
var myProperty: String!

init() {
super.init()
self.setupMyProperty()
}

func setupMyProperty() {
self.myProperty = "x"
}
}

page 499 of "The Swift Programming Language" manual

Calling an instance method in designated initializer of a Swift class

As you correctly mentioned the compiler complains about the "Use of self in method call 'parseString' before super.init initialises self". The reason for that is that the compiler has to ensure that you do not access anything on self before it did finish initializing. Because the compiler does not want to (or even can not) check every outgoing method call before the initialization finished it simply disallows any usage of self before it finished.

Luckily your method parseString does not want to change or access any property. Therefore you can and should make it a non-instance function. If it has nothing do with the instance of FooBar, why should it have be only available on an instance of FooBar?

You can simply make it a static or class function as you already did, which is perfectly fine.

But I would go even further and move it completely out of FooBar. There are a few options for that:

  • create a class Helper where you define it as a class function as well
  • create a class Helper where you define it as instance function and create a Helper instance in your class FooBar or create a global one and pass that one in the init as well.

How to call instance method inside class using Swift

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

Passing instance method as callback in class initializer

Here's another option:

class Foo {
let bar: Bar

init() {
self.bar = Bar(callback: self.handler)
}

let handler: () -> Void = {
print("handled")
}
}

Maybe it doesn't feel quite as hacky, but if handler deals with self at all, this won't work. You can't do it with a Delegate either.

Yea, AFAIK, the only way to do this is to make bar an implicitly unwrapped var

class Foo {
var bar: Bar!

init() {
bar = Bar(callback: handler)
}

func handler() {
print("Handled")
}
}

Use Function in Initializer - Swift?

I think it is not the greatest solution but still it is working.

 class A {
var variable : Int

init() {

self.variable = A.assign(1)

}

private class func assign(y : Int) -> Int {
return y
}
}

Initialising member to class function causes 'self' used in method call error

It might be better to not use a Bool, but rather a nested Enum, which is also more extendible if you wanna add some other modes of haptic feedback later on.

I have a generalized solution for a generalized problem of your question. So either you do:


public class FunctionOwner {

private let mode: Mode

public init(`do` mode: Mode = .default) {
self.mode = mode
}
}

public extension FunctionOwner {

enum Mode {
case foo, bar
}

func fooOrBar() {
switch mode {
case .foo: foo()
case .bar: bar()
}
}
}

private extension FunctionOwner {
func foo() {
print("doing foo")
}

func bar() {
print("doing bar")
}
}

public extension FunctionOwner.Mode {
static var `default`: FunctionOwner.Mode {
return .foo
}
}

// USAGE
FunctionOwner(do: .bar).fooOrBar() // prints "doing foo"
FunctionOwner(do: .foo).fooOrBar() // prints "doing bar"

Or if you for some reason do want to keep the stored Mode, you can do this (might be relevant for your actual question on how you do a workaround of referencing self in the init.):

public class FunctionOwner {

private let _function: (FunctionOwner) -> Void

public init(`do` mode: Mode = .default) {
_function = { functionOwner in
switch mode {
case .foo: functionOwner.foo()
case .bar: functionOwner.bar()
}
}
}
}

public extension FunctionOwner {

enum Mode {
case foo, bar
}

func fooOrBar() {
_function(self)
}
}

// The rest of the code is the same as the example above

Swift. Use of 'self' in method call before all stored properties are initialized

You can't call methods on self before all non-optional instance variables are initialized.
There are several ways to go around that.

  1. Change properties to optionals or implicitly unwrapped optionals
    (not recommended)
  2. Make the buildCircle() method static or just a
    function in the file and call the addSubview() for all the circles
    after all of the properties were initialized and you called
    super.init()
  3. etc. You just have to avoid calls to self before the
    class was initialized.

Trouble calling a method in an init

You cannot use self before all the stored properties have been initialised

The rule is simple and you are violating it here

self.date = getDateString()

infact this line is equivalente to

self.date = self.getDateString()

and as you can see you are using self while date has not been initialised yet.

You must init date before calling the instance method getDateString().

A class method

If you really want to call a method to initialize date it must be a class method

class SomeClass {

let title: String
let content: String
let date: String?

init(title: String, content: String) {

self.title = title
self.content = content
self.date = SomeClass.getDateString()

}

class func getDateString() -> String {
return "A date"
}
}

A few improvements

  1. If then date should contain... a Data then its type should be NSDate, not String
  2. If the date property should indicate the time when the value has been created then you can assign it = NSDate() on the declaration of the property
  3. created is a better name for this property

These 3 suggestions comes from the comment of user user3441734.

This is the updated code

class SomeClass {
let title: String
let content: String
let created = NSDate()

init(title: String, content: String) {
self.title = title
self.content = content
}
}

Swift. Use of 'self' in method call before all stored properties are initialized

You can't call methods on self before all non-optional instance variables are initialized.
There are several ways to go around that.

  1. Change properties to optionals or implicitly unwrapped optionals
    (not recommended)
  2. Make the buildCircle() method static or just a
    function in the file and call the addSubview() for all the circles
    after all of the properties were initialized and you called
    super.init()
  3. etc. You just have to avoid calls to self before the
    class was initialized.


Related Topics



Leave a reply



Submit