0

I think it's pretty common problem, but I haven't found the solution. Here is the code:

class ViewController: UIViewController {

    @IBOutlet weak var monthLabel: UILabel!
    
    let date = Date()
    let calendar = NSCalendar.current
    let month = calendar.component(.month, from: date)
    //let month = calendar.component(.month, from: date)
    //let day = calendar.component(.weekday, from: date)
    //let dateDay = calendar.component(.day, from: date)
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // some code
    }

    @objc func addStory(sender: UIButton!) {
        print("Button tapped")
        self.performSegue(withIdentifier: "addStory", sender: self)
    }
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "addStory"{
            let destinationVC = segue.destination as! ResultsViewController
           // destinationVC.currentDayKey =
        }
    }
}

When I try to build it I get the "Cannot use instance member 'calendar' within property initializer; property initializers run before 'self' is available" and "Cannot use instance member 'date' within property initializer; property initializers run before 'self' is available"

But if I initialise month, day and dateDay in viewDidLoad everything works. How to declare them on the top?

I've tried to find some solutions with same error, but nothing helped

tadman
  • 208,517
  • 23
  • 234
  • 262
ezhovich
  • 19
  • 3
  • Your error is likely on the `let month = ...` line, as this uses another variable (`calendar`) before the class is initialized. I would take a look at [this question](https://stackoverflow.com/q/43550813/20384561). –  Mar 01 '23 at 20:06
  • 1
    Does this answer your question? [How to initialize properties that depend on each other](https://stackoverflow.com/questions/25854300/how-to-initialize-properties-that-depend-on-each-other) – HangarRash Mar 01 '23 at 20:07

1 Answers1

0

But if I initialise month, day and dateDay in viewDidLoad everything works. How to declare them on the top?

The error is specifically telling you that you can't initialize a property in terms of another property. Instead, you'll need to set the property after the property initializers have run. The way to do that is to provide an initializer for the class.

Here's a simpler version of your problem code:

class Foo {
    var date = Date()
    let calendar = NSCalendar.current
    var month: calendar.component(.month, from:date)
}

That last line causes an error because it uses date, which is also a property. Adding an init method that sets month solves the problem:

class Foo {
    var date = Date()
    let calendar = NSCalendar.current
    var month: Int
    
    init() {
        month = calendar.component(.month, from:date)
    }
}

Notice that if you initialize a property in init, you have to specify the type explicitly — the compiler can't infer the type if there's no value to infer it from.

Incidentally, it seems likely that you might always want month and date to agree, so it might make more sense to make month a computed property, in which case you don't need the init, and you might not need a separate calendar property either. Note also that in Swift you can use Calendar instead of NSCalendar:

class Foo {
    var date = Date()
    var month: Int {
        Calendar.current.component(.month, from: date)
    }
}
Caleb
  • 124,013
  • 19
  • 183
  • 272