Swift: Call Self Method Inside Init

Swift: Call self method inside init

No, it's not a defect, simply self cannot be referenced in an initializer until all stored properties have been initialized, and a super class initializer has been invoked (if any).

In your case it seems legit to do the initializations in a method, and call that from the initializer, but unfortunately it doesn't work.

Possible solutions:

  • make the properties optional or implicitly unwrapped (discouraged, unless you really need them optionals)
  • initialize the properties with fake values before calling reset:

    init() {
    self.a = 0
    self.b = 0
    self.c = 0
    self.d = 0

    reset()
    }

    or

    var a = 0
    var b = 0
    var c = 0
    var d = 0

    init() {
    reset()
    }

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

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

Use of self in method call before super.init initializes self', can't init properties through a method call

Form documentation:

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.

You need to set value for instance variable before you call super.init() And after this action you will access to call instance methods. In your case you can do this:

override init (frame : CGRect) {
self.collectionView = UICollectionView()
super.init(frame : frame)
// Now you can call method
self.someMethod()
}

ADD for question's EDIT:

You can't call method before super.init() call because of safety reasons. If you will do it then your method can use some properties which have not yet been initialized in the parent class

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.

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

It doesn't mean that if you haven't written self with function call f then it will not reference to self as of f is still instance method, so with init it must be called after all the instance properties are initialized means after the the instance of class is initialized. So simply call f() after you initialized the instance property a.

class A {
var a: String
init(a: String) {
self.a = a
f()
}

func f() {
print("HeHe")
}
}

Use of self in method call before super.init initialises self

You are not calling super.init(frame:) from your init(frame:viewController method. It needs to be done between setting self.currentViewController and calling setup.

init(frame: CGRect, viewController: UIViewController) {
self.currentViewController = viewController

super.init(frame: frame)

setup()
}

You should read the Initialization chapter (especially the Class Inheritance and Initialization section) of the Swift book. Initialization of a class needs to be done in a clearly documented fashion.

How to set delegate to self inside init function?

The error message told you what needs to be done, you need to call super.init() in your init.

class MQTTController:NSObject, CocoaMQTTDelegate {
static let sharedInstance = MQTTController()
var clientID:String
var mqtt:CocoaMQTT
private override init() {
clientID = "xyz-" + String(ProcessInfo().processIdentifier)
mqtt = CocoaMQTT(clientID: clientID, host: "mqttcontroller.mqtt.net", port: 1883)
mqtt.username = "myusername"
mqtt.password = "mypassword"
mqtt.willMessage = CocoaMQTTWill(topic: "/will", message: "dieout")
mqtt.keepAlive = 30
mqtt.cleanSession = true
MQTTController.isConnecting = true

super.init() // This line was missing

mqtt.delegate = self
mqtt.connect()
}
}

Instantiate Self outside of init in Swift

You may use the (dynamically typed) metatype returned by type(of:) to access an initializer of the concrete type of the metatype. Quoting the Language Reference - Metatypes

Use an initializer expression to construct an instance of a type from
that type’s metatype value. For class instances, the initializer
that’s called must be marked with the required keyword or the entire
class marked with the final keyword.

So in your case, you could use the metatype of self to call a required initializer of the concrete type of self, e.g.

func myCustomCopy() -> Self {
return type(of: self).init()
}

Note that, as specified in the quote above, since you are working with a non-final class, the initializer must be a required one.



Related Topics



Leave a reply



Submit