3

I want CurrendData.location to get its random value once CurrentData gets initialized. I came up following code:

struct CurrentData {
    var size: (x: Int, y: Int)
    var location: (x: Int, y: Int)
        
    init(size: (x: Int, y: Int)) {
        self.size = size
        self.location = (getRandom(size.x), getRandom(size.y)) //error
    }
    
    private func getRandom (_ value:Int) -> Int {
        return Int.random(in: 0...value-1)
    }
}

But I get this error: "'self' used before all stored properties are initialized". How can it be fixed?

Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116
  • Does this answer your question? [Trouble calling a method in an init](https://stackoverflow.com/questions/34380726/trouble-calling-a-method-in-an-init). Note that for a struct a `static func` is the same as `class func` for a class – Joakim Danielson Oct 05 '20 at 11:44

2 Answers2

6

getRandom is an instance method, so it is called on self (however, Swift lets you omit self when accessing instance methods/properties).

If you want to be able to call a function from init, you need to declare it as a static method rather than an instance method. You can then call the static method by writing out the type name (CurrentData) or simply using Self.

struct CurrentData {
    var size: (x: Int, y: Int)
    var location: (x: Int, y: Int)
        
    init(size: (x: Int, y: Int)) {
        self.size = size
        self.location = (Self.getRandom(size.x), Self.getRandom(size.y))
    }
    
    private static func getRandom (_ value:Int) -> Int {
        Int.random(in: 0...value-1)
    }
}
Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116
3

Instead defining your getRandom as an instance method, define it as a static one, then reference it by a type name (CurrentData) or Self

struct CurrentData {
    var size: (x: Int, y: Int)
    var location: (x: Int, y: Int)
        
    init(size: (x: Int, y: Int)) {
        self.size = size
        location = (Self.getRandom(size.x), Self.getRandom(size.y))
    }
    
    private static func getRandom (_ value:Int) -> Int {
        Int.random(in: 0...value-1)
    }
}

Other solution is to define your locationproperty as a lazy one, then the self is accessible and the location will be executed only once and after being called in the code.

struct CurrentData {
    var size: (x: Int, y: Int)
    lazy var location: (x: Int, y: Int) = {
        (getRandom(size.x), getRandom(size.y))
    }()
        
    init(size: (x: Int, y: Int)) {
        self.size = size
    }
    
    private func getRandom (_ value:Int) -> Int {
        Int.random(in: 0...value-1)
    }
}
Blazej SLEBODA
  • 8,936
  • 7
  • 53
  • 93