swahili
(Swahili)
1
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
}
}
Lantua
2
IIRC, didSet/willSet won't trigger inside init.
PS
There's [isMultiple(of:)] function that you might be interested.
Nevin
4
Also, you can make isLeapYear a computed property:
var isLeapYear: Bool {
// Calculate and return the value here
}
swahili
(Swahili)
5
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.
swahili
(Swahili)
7
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 ().)