I feel like the answer is obvious, but I haven't been able to figure this out and it seems to be a recurring problem for me. Basically I want to do something like this:
extension NSData {
convenience init(JSONObject: AnyObject) {
do {
self = try NSJSONSerialization.dataWithJSONObject(JSONObject, options: [])
}
catch {
self = nil
}
}
}
However it won't let me simply assign a value to self. I do this all the time with enums, but it won't let me do it with classes. Is there any way implement at convenience initializer using an instance of the class created in the initializer implementation?
Saying that factory initializers are "not supported yet" in Swift is fallacious. Their exclusion is a design decision, and their use intended to be covered by failable initializers; quoting the following Apple Swift blog post
Failable initializers eliminate the most common reason for factory methods in Swift, which were previously the only way to report failure when constructing this object.
...
Using the failable initializer allows greater use of Swift’s uniform construction syntax, which simplifies the language by eliminating the confusion and duplication between initializers and factory methods.
So in your case, you're probably looking for a convenience failable initializer. E.g., something along the lines
extension NSData {
convenience init?(JSONObject: AnyObject) {
do {
let foo = try NSJSONSerialization.dataWithJSONObject(JSONObject, options: [])
self.init(data: foo)
}
catch {
return nil
}
}
}
/* Example usage */
let foo : AnyObject = ["Foo":"bar"]
let bar = NSData.init(JSONObject: foo)
In the title of your question you include "... instead of calling an existing init". When making use of convenience
initializer, a designated initializer (of same class) must be called at some point (even via other convenience initializers). From the Swift Language Guide - Initialization - Class Inheritance and Initialization:
...
Rule 2
A convenience initializer must call another initializer from the same class.
Rule 3
A convenience initializer must ultimately call a designated initializer.
The example code above, however, allows an early escape (failure) of the convenience initializer if NSJSONSerialization.dataWithJSONObject(...)
fails, but if it succeeds, sooner or later a designated initializer needs to be called (in this case init(data:)
designated initializer).
For details on failable initializers, see the Swift Language Guide - Initialization - Failable Initializers. For an additional remark regarding the initializer chain (convenience -> ... -> designated initializer
), see rickster:s comment below.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With