Ricardo Amores
Ricardo Amores

Reputation: 4687

Swift class: declare variables with closures pointing to member functions

Using swift 4.2 with xcode10 beta

I'm trying to create a swift class that stores as a field, a closure that will point to a member function of the class.

The idea is a variation to the Strategy pattern. I want to be able to change what function is called at runtime. In this example, the public f() function calls the internal closure. The closure should store either f_release or f_debug, where the later just add some debugging print statements:

class MyClass {

    var n:Int = 0
    var aFunc: (Int) -> ()

    init() {
        aFunc = f_release
    }

    public func f(number:Int) {
        aFunc(number)
    }

    func f_release(number:Int) {
        n = n + number
    }

    func f_debug(number:Int) {
        print(n)
        f_release(number:number)
        print(n)
    }
}

My problems comes at the initialization. In the example above the compiler complains: _'self' used in method call 'f_release' before all stored properties are initialized_

I've tried initializing the aFunc variable with a default value to fix this problem replacing line

    var aFunc: (Int) -> ()

with line

    var aFunc: (Int) -> () = f_release

However for that case, the compiler now complains with: Cannot convert value of type '(MyClass) -> (Int) -> ()' to specified type '(Int) -> ()'

What I am doing wrong? Thanks in advance

Upvotes: 1

Views: 1255

Answers (2)

David Pasztor
David Pasztor

Reputation: 54795

Assigning the value inside the initializer cannot work, since you are trying to assign an instance property (or function in your specific case) to another instance property, but in the initializer, neither of them are guaranteed to be initialized.

You can solve your problem by declaring aFunc as lazy. You won't need an initializer anymore either.

lazy var aFunc: (Int) -> () = f_release

Upvotes: 2

Nader
Nader

Reputation: 1148

Try this:

 class MyClass {

    var n:Int = 0
    lazy var aFunc: (Int) -> () = f_release

    public func f(number:Int) {
        aFunc(number)
    }

    func f_release(number:Int) {
        n = n + number
    }

    func f_debug(number:Int) {
        print(n)
        f_release(number:number)
        print(n)
    }
}

Upvotes: 2

Related Questions