0

How to implement a failable initializer for a class conforming to NSCoding protocol?

I'm getting the following errors:
1. Line override init() {}: Property 'self.videoURL' not initialized at implicitly generated super.init call
2. Line return nil: All stored properties of a class instance must be initialized before returning nil from an initializer

I've seen Best practice to implement a failable initializer and All stored properties of a class instance must be initialized before returning nil which helped me a lot, but since my class also conforms to NSCoding protocol I don't know how to implement a failable initializer in my case.

Any suggestions on how to implement a failable initializer?

class CustomMedia : NSObject, NSCoding {
  var videoTitle: String?
  let videoURL: NSURL!

  override init() {}

  init?(title: String?, urlString: String) {
    // super.init()
    if let url = NSURL(string: urlString) {
       self.videoURL = url
       self.videoTitle = title
    } else {
       return nil
    }
  }

  func encodeWithCoder(aCoder: NSCoder) {
    aCoder.encodeObject(self.videoTitle, forKey: PropertyKey.videoTitle)
    aCoder.encodeObject(self.videoURL, forKey: PropertyKey.videoURL)
  }

  required init(coder aDecoder: NSCoder) {
    videoTitle = aDecoder.decodeObjectForKey(PropertyKey.videoTitle) as? String
    videoURL = aDecoder.decodeObjectForKey(PropertyKey.videoURL) as! NSURL
  }
}
Community
  • 1
  • 1
Andrej
  • 7,266
  • 4
  • 38
  • 57
  • 1
    Why are you doing the `override init() {}`? – Dan VanWinkle Nov 23 '15 at 20:49
  • @DanVanWinkle I've seen it implemented in this way in other examples for conforming to NSCoding and it wasn't causing any errors. Great, I've commented it out and the first error disappeared. – Andrej Nov 23 '15 at 21:03

1 Answers1

0

UPDATE: This was addressed in the Swift 2.2 update, and you no longer have to assign a nil value and call super prior to failing an initializer.

For version of Swift prior to 2.2:

You actually have to initialize your values before returning nil, unfortunately.

Here's the working solution:

class CustomMedia : NSObject, NSCoding {
   var videoTitle: String?
   var videoURL: NSURL!

   init?(title: String?, urlString: String) {
      super.init()

      if let url = NSURL(string: urlString) {
         self.videoURL = url
         self.videoTitle = title
      } else {
         self.videoURL = nil
         self.videoTitle = nil
         return nil
      }
   }

   func encodeWithCoder(aCoder: NSCoder) {
      aCoder.encodeObject(self.videoTitle, forKey: PropertyKey.videoTitle)
      aCoder.encodeObject(self.videoURL, forKey: PropertyKey.videoURL)
   }

   required init(coder aDecoder: NSCoder) {
      videoTitle = aDecoder.decodeObjectForKey(PropertyKey.videoTitle) as? String
      videoURL = aDecoder.decodeObjectForKey(PropertyKey.videoURL) as! NSURL
   }
}
Charles A.
  • 10,685
  • 1
  • 42
  • 39
  • How can I do that? I've put `videoURL = NSURL(string: "https://www.google.com/")!` before returning nil, but it didn't work. Sitll getting the error: All stored properties of a class instance must be initialized before returning nil from an initializer. – Andrej Nov 23 '15 at 21:11
  • I had to put the above code before returning nil AND also I had to clean the project. Otherwise I was getting the above error. Couldn't figure it out since I'm not cleaning the project before every build. – Andrej Nov 23 '15 at 21:24
  • @Andrej You can just assign nil since the type is optional, you don't have to make a valid URL. – Charles A. Nov 23 '15 at 21:39
  • No, videoURL is not optional so I can't set it to nil. Only videoTitle is optional an it doesn't need to be initialised before returning nil. Maybe you didn't pay attention to "!" in `var videoURL: NSURL!` – Andrej Nov 23 '15 at 21:45
  • 1
    `NSURL!` is an optional type, it's an implicitly unwrapped optional. You just can't reference it while it's `nil` without causing a crash. You can absolutely assign `nil` though. – Charles A. Nov 23 '15 at 22:26
  • This was a Swift bug that is now fixed in Swift 2.2, you can now properly define a failable initiazliers for class as you would for structs before 2.2. – AmitP Apr 14 '16 at 11:58