0

I have a hierarchy of 2 classes in Swift 2.0. Both classes can be instantiated by passing the arguments or by passing a JSON dictionary ([String: AnyObject]) which contains the arguments.

The inits that directly take the arguments are designated inits, while those that take the JSON are convenience inits with the same signature.

class Thing {
    let name : String

    init(name: String){
        self.name = name
    }

    convenience init(jsonNamed: String){

        // read the json, parse and extract
        // the name
        self.init(name: "got this from JSON")
    }
}

class SubThing : Thing{

    var surname : String

    init(name: String, surname: String){
        self.surname = surname
        super.init(name: name)
    }


    convenience init(jsonNamed: String){

        self.init(jsonNamed: "got this from JSON")
        // extract surname
        self.surname = "Got this from json"


    }

}

The convenience init in SubThing is not allowed to call the same init in super, and if I call it in self, it will cause an infinite recursion, as both methods have the same signature.

If I make both json inits designated ones, I can't call self.init(name:) in Thing, and I would have to repeat the same code in both initialisers in Thing.

What's the best way to get around this kind of situation?

cfischer
  • 24,452
  • 37
  • 131
  • 214

1 Answers1

2

You're doing a loop in SubThing calling the same designated initializer from itself. I see it rewritten this way:

class Thing {
    private var name : String?

    private init() {}

    convenience init(name: String){
        self.init()
        self.name = name
    }

    convenience init(jsonNamed: String){
        self.init()
        self.name = getNameFromJSON()
    }

    private func getNameFromJSON() -> String {
        // read the json, parse and extract
        // the name
        return "got this from JSON"
    }
}

class SubThing : Thing {
    private var surname : String?

    convenience init(name: String, surname: String){
        self.init(name: name)
        self.surname = surname
    }


    convenience init(jsonNamed: String){
        self.init()
        self.name = getNameFromJSON()
        // extract surname
        self.surname = "Got this from json"
    }
}

Tested and working. UPDATE: added private inits, so it couldn't be initialized empty.

rshev
  • 4,086
  • 1
  • 23
  • 32
  • I decided to move all the json parsing out of the inits and into a function that returns a struct with all the correct and typed info, similar to what [Aeson](https://www.fpcomplete.com/school/starting-with-haskell/libraries-and-frameworks/text-manipulation/json) does for Haskell. You answer set me in the right direction, thanks! :-) – cfischer Aug 06 '15 at 16:40