Search code examples
swiftinitialization

How can I breakup a large init (due to a large quantity of computations), for better readability?


I have a class, with say 100 properties (exaggeration). Most of these properties must be computed, based off of user preferences.

These properties will not change after the initialization, which is why I would like to run the computations once at the beginning, and set the results into let properties

Users can set tens of preferences, and depending on the combination of preferences set, the properties here will change when I initialize an object.

let prop1:String
let prop2:String
...
let prop100:String

init(maybeRelevantArg:Int, maybeRelevantArg2:String) {
    var proposedProp1 = ""
    //20 lines of logic to compute proposedProp1, referencing preferences and maybeRelevantArgs
    self.prop1 = proposedProp1

    var proposedProp2 = ""
    //20 lines of logic to compute proposedProp2, referencing preferences and maybeRelevantArgs
    self.prop2 = proposedProp2
}

You get the point, at this point my init will be hundreds of lines long, basically unreadable.

I would like to separate these chunks of logic out into separate methods, something like:

init(maybeRelevantArg:Int, maybeRelevantArg2:String) {
    self.computeAndSetProp1(relevantArg:maybeRelevantArg1)
    self.computeAndSetProp2(relevantArg:maybeRelevantArg2)
}

func computeAndSetProp1(relevantArg:String) {
    var proposedProp1 = ""
    //20 lines of logic to compute proposedProp1, referencing preferences and relevantArgs
    self.prop1 = proposedProp1
}

This way the init is much more readible, and it should be easier to debug and maintain.

The issue is that obviously the compiler won't be happy that my init method is not explicitly initializing these properties, and I get something akin to:

'self' used before all stored properties are initialized

and also, inside of computeAndSetProp1(), I will get this error:

cannot assign to property: 'prop1' is a 'let' constant

Is there a way to split up this large init?


Solution

  • You can make the computeAndSetProp1() function be a free function (that is, not part of any class), like this:

    func computeAndSetProp1(relevantArg: String) -> String {
        var proposedProp1 = ""
        //20 lines of logic to compute proposedProp1, referencing preferences and relevantArgs
        return proposedProp1;
    }
    
    class someClass: NSObject {
        let prop1 : String
        let prop2 : String
        override init() {
            prop1 =  computeAndSetProp1(relevantArg: "x")
            //...etc.
        }
    }
    

    I'd also recommend seeing if you can generalize the computeAndSetProp* functions to reduce the amount of code. You can always post the code on Code Review to get more ideas about how to simplify the code.