3

I've created a computed static property for which I'd like to have it computed once and whenever accessed after then will just return the original computed value. lazy properties appear to be what I want but after a bit of searching it appears static properties are lazy by default.

When I run the following code it comes out fine the first time it is accessed/ if I run each unit test individually. However when I access this a 2nd time I'm given an empty array.

static var att: [ConferenceNumber] = {
    let list = buildDirectory(for: .att, from: jsonArray)
    return list
}()

private static let jsonArray: [Any]? = {
    let numbersFilePath = Bundle.main.path(forResource: "numbers", ofType:"json")
    let data = try! Data(contentsOf: URL(fileURLWithPath:numbersFilePath!), options: .uncached)

    return try! JSONSerialization.jsonObject(with: data) as? [Any]
}()

Code where this is called a 2nd time and returns an empty array

private static func isAttMeeting(meetingText: String, parsedPhoneNumbers: [String]) -> Bool {
    let attPhoneNumbers = ConferenceNumberDirectory.att.map{$0.number}
    let attNumberWasParsed = parsedPhoneNumbers.intersects(with: attPhoneNumbers)
    if attNumberWasParsed {
        return true
    }
    return meetingText.contains(pattern: attURLRegex) || meetingText.contains(pattern: attURLRegex2)
}
Declan McKenna
  • 4,321
  • 6
  • 54
  • 72

1 Answers1

6

Your solution should work. Maybe there is something wrong with some other part of your code. Take a look at the following example:

var myStrings = ["a", "b"]

class SomeClass {
    static let strings: [String] = {
        return myStrings
    }()
}

print("myStrings: \(myStrings)")
print("static strings: \(SomeClass.strings)")

myStrings.append("c")

print("myStrings: \(myStrings)")
print("static strings: \(SomeClass.strings)")

Prints:

myStrings: ["a", "b"]
static strings: ["a", "b"]
myStrings: ["a", "b", "c"]
static strings: ["a", "b"]

So for you the following piece of code should work:

class ConferenceNumberDirectory {
    static let att: [ConferenceNumber] = {
        return buildDirectory(for: .att, from: jsonArray)
    }()
}
André Slotta
  • 13,774
  • 2
  • 22
  • 34
  • Looks like you're right I was too quick to assume this was being written to twice when it appears another test had set these values to empty before the current test could assign anything to them. – Declan McKenna Aug 18 '17 at 13:44