swiftdelegatesdatasourceinit

Run a function just after init() completes in Swift


I am testing to run delegation pattern from initializers. Here is my data supplier test class and its' data source :

protocol MyClassDataSource : AnyObject{
    func returnString(string: String)
}

protocol MyClassProtocol: AnyObject {
    var dataSource : MyClassDataSource? { get set }
}

class MyClass : MyClassProtocol {
    weak var dataSource: MyClassDataSource?
    
    init() {
        print("1. My Class initialized")
        getString()
    }

    func getString() {
        let myString = "Hello World"
        print("3. The getString func run")
        dataSource?.returnString(string: myString)
    }
}

I send data to my other class. Here it is :

class OtherClass : MyClassDataSource {
    
    weak var myClass : MyClassProtocol?
    
    init(myClass: MyClassProtocol?) {
        self.myClass = myClass
        self.myClass?.dataSource = self
        print("2. MyClass delegate set")
    }
    
    func returnString(string: String) {
        print("4. Delegate run and print the string: \(string)")
    }
}

Then I initialize them :

let myClass = MyClass()
let otherClass = OtherClass(myClass: myClass)

I want to create my class and send data from MyClass to OtherClass. I wanted to use init() functions to set dataSource to self and also run a function and send data. Of course, it didn't work. What I expected to see printed in the console :

  1. My Class initialized
  2. MyClass delegate set
  3. The getString() func run
  4. DataSource run in OtherClass and print the string: Hello World

But getString() immediately run, before setting or creating the OtherClass and prints this :

  1. My Class initialized
  2. The getString() func run
  3. MyClass delegate set

If I manually delay the getString() run, it works :

    func getString() {
        let myString = "Hello World"
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in
            print("3. The getString func run")
            self?.dataSource?.returnString(string: myString)
        }
    }

So, my question is, how can I make it work? Can I set the delegate and send data between just by initializing the classes? Is it possible to do it somehow?


Solution

  • Calling getString in init is not possible. You want the data source to be set before getString is called, but getString is called in init, so there is no chance for other code to set the data source. Other code can only set the data source after init.

    To achieve this sequence of events, you can call getString immediately after dataSource has been set. That is the earliest point at which you can meaningfully call getString - returnString will not be called any time before that.

    weak var dataSource: MyClassDataSource? {
        didSet { 
            print("2. MyClass delegate set")
            getString() 
        }
    }