How to use didSet/willSet when init a property?

Hi,

I'm checking how property observers work, so did the following test that fails for some reason that I'd like to understand:

class Year {
    var calendarYear: Int = 0 {
        didSet {
            self.isLeapYear = (self.dividesBy(4) && !self.dividesBy(100)) || self.dividesBy(400)
        }
    }
    var isLeapYear: Bool = false
    
    init(calendarYear: Int) {
        self.calendarYear = calendarYear
    }
    
    func dividesBy (_ num: Int) -> Bool {
        return self.calendarYear % num == 0
    }
}

Working version is:

class Year {
    var calendarYear: Int
    var isLeapYear: Bool = false
    
    init(calendarYear: Int) {
        self.calendarYear = calendarYear
        self.isLeapYear = (self.dividesBy(4) && !self.dividesBy(100)) || self.dividesBy(400)
    }
    
    func dividesBy (_ num: Int) -> Bool {
        return self.calendarYear % num == 0
    }
}

IIRC, didSet/willSet won't trigger inside init.

PS

There's [isMultiple(of:)] function that you might be interested.

Ok thanks!

Also, you can make isLeapYear a computed property:

var isLeapYear: Bool {
  // Calculate and return the value here
}

Right, good point! Thanks ;)

The computed property is probably the best strategy for the originally posted code.

But for anyone who comes here actually needing this, the best way I know of for working around init’s (necessary) skipping of property observers is to use this pattern:

class SomeClass: Superclass {
  init() {
    observedProperty = Something()
    defer { self.observedPropertyDidSet() }

    // Other set‐up.
    super.init()
  }

  var observedProperty: Any {
    didSet {
      observedPropertyDidSet()
    }
  }
  private func observedPropertyDidSet() {
    print("The observed property has been set.")
  }
}

Better suggestions are welcome if they exist.

Thanks @SDGGiesbrecht

I've actually followed the computed properties advice for a new exercise. But for the particular case where the type is DateFormatter I've omitted () causing an error cannot convert type () -> _ to specified type DateFormatter, since I'm just starting with swift from the very basics, I believe that I've assigned a closure and not the return value, for that reason had to call the closure immediately when declared (Immediately Invoked Function Expression (IIFE)). Is that correct?

struct Gigasecond {
    private let gigaSecond: Double = 1000000000
    let dateFormatter: DateFormatter = {
        let df = DateFormatter()
        df.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
        df.timeZone = TimeZone(abbreviation: "GMT")
        return df
    }()
    var description: String = ""

    init? (from: String) {
        if let userInputDate = dateFormatter.date(from: from) {
            let computedDate = userInputDate.addingTimeInterval(self.gigaSecond)
           description = dateFormatter.string(from: computedDate)
        }
    }
}

Yes, you are correct about ().

To clarify the difference:

var constructedOnceAndReused: DateFormatter = {
  return // ...
}()

var constructedAnewEachTime: DateFormatter {
  return // ...
}

(Notice the = and the ().)