40

If I create a swift struct with no init, then I can call the compiler-generated default memberwise initialiser, like so:

struct OrderFill {
    let price:Int
    let qty: Int
    let timeStamp: NSDate
}
let o = OrderFill(price: 2, qty: 1, timeStamp: someDate)

What I'd like to do is create a convenience init method to deserialise from a dictionary, which then chains to the default memberwise init. Something like

struct OrderFill {
    let price:Int
    let qty: Int
    let timeStamp: NSDate

    init(dict:[String:AnyObject]) throws {
        self.init(
            price: dict["price"] as! Int
            qty: dict["qty"] as! Int
            timeStamp: try parseDate(dict["ts"] as! String)
    }
}
let o = OrderFill(someDict)

When I try write this code though, the compiler (Xcode 7.2) gives me the error "Extra argument 'qty' in call" as though it doesn't see the default memberwise and is trying to recursively call init(dictionary)

I can write my own memberwise init, or I can simply assign the properties directly from my init(dictionary), but it'd be nice if I could chain the call. Is there any way to do this in swift?

1
  • It's just one of those weird things™ - you have to put it in an extension, and that's all there is to it. Commented Sep 5, 2023 at 20:44

2 Answers 2

97

Add your own initializer as an extension to your struct. Extensions cannot remove existing functionalities, so it will preserve struct's default initializer.

struct OrderFill {
    let price: Int
    let qty: Int
    let timeStamp: NSDate
}

extension OrderFill {

    init(dict: [String: AnyObject]) throws {
        self.init(
            price: dict["price"] as! Int,
            qty: dict["qty"] as! Int,
            timeStamp: try parseDate(dict["ts"] as! String)
        )
    }
}

let o = OrderFill(someDict)
Sign up to request clarification or add additional context in comments.

2 Comments

May seem hacky, but it's also in the book... NOTE If you want your custom value type to be initializable with the default initializer and memberwise initializer, and also with your own custom initializers, write your custom initializers in an extension rather than as part of the value type’s original implementation. For more information, see Extensions.
This is totally strange, it works in extension but not in the struct itself. What is the logic behind it?
9

From the apple docs about Initialization:

Structure types automatically receive a memberwise initializer if they do not define any of their own custom initializers

and

Note that if you define a custom initializer for a value type, you will no longer have access to the default initializer (or the memberwise initializer, if it is a structure) for that type. This constraint prevents a situation in which additional essential setup provided in a more complex initializer is circumvented by someone accidentally using one of the automatic initializers instead.

Therefore the answer is NO. You cannot provide a custom initializer and use the memberwise initializer at the same time.

It sounds like this swift evolution proposal talks about extending the capabilities of the current memberwise initializer. But of course that is not out yet, you can however still take a look to learn a bit about what the limitations of the current situation are.

1 Comment

Custom initializers alongside the default memberwise initializers are now possible. Just put the custom initalizer in an extension: hackingwithswift.com/example-code/language/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.