UPnAtom icon indicating copy to clipboard operation
UPnAtom copied to clipboard

Swift 1.2: Compiler forces immutable (let) properties to be initialized in phase 1 of object initialization before super.init is called

Open master-nevi opened this issue 11 years ago • 0 comments

Swift 1.2 Release notes: "Previously, immutable (let) properties were completely mutable within the body of initializers. Now, they are only allowed to be assigned to once to provide their value". Fails to mention that they can only be initialized once AND only during phase 1 of initialization, before super.init is called. My guess is that due to their mutability within the initializer body, they were actually set to nil before super.init in phase 1 and then set to an actual value when self was usable in phase 2.

Code in Documentation now fails: https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html#//apple_ref/doc/uid/TP40014097-CH20-ID55

Dev Forum Discussions:

  • https://devforums.apple.com/message/1104945#1104945
  • https://devforums.apple.com/message/1109362#1109362
  • https://devforums.apple.com/message/1117014#1117014
  • https://devforums.apple.com/thread/264001?tstart=150

Current workaround is to turn these constants into implicitly unwrapped privately set variables since

  • Variables can be mutated at any point during initialization
  • Implicitly unwrapped means they can be nil before self is reference but can be safely assumed to contain something afterwards
  • Privately set as to keep them from being set outside of the class similarly to being constant.
// from
public let serviceID: String!

// to
public private(set) var serviceID: String!

required public init?(usn: UniqueServiceName, descriptionURL: NSURL, descriptionXML: NSData) {
        super.init(usn: usn, descriptionURL: descriptionURL, descriptionXML: descriptionXML)

        // self is referenced for the parser
        let serviceParser = UPnPServiceParser(upnpService: self, descriptionXML: descriptionXML)
        let parsedService = serviceParser.parse().value

        if let serviceID = parsedService?.serviceID {
            self.serviceID = serviceID
        }
        else { return nil }
...

master-nevi avatar Mar 27 '15 18:03 master-nevi