Search code examples
swiftinheritanceinitializer

Inheritance and initialization in swift


I have been trying to create two different classes: for the superclass I create my properties and init() function with the appropriate parameters. However, when I create my subclass with its own properties and init() function I get into trouble.

What I'm trying to achieve here is that at some point in my app, the user will enter a bunch of fields and when he/she is ready and clicks the 'ready' button, the content of the fields will be used as arguments for my init() function of the subclass. The superclass's init() has less parameters than the init() of the subclass.

I've been reading about designated and convenience initializer but I'll a bit confused. Maybe I don't really need them, I'm not sure.

What i'm trying to avoid is having to change the value of any of the properties of the subclass manually after the call to init().

Any help is much appreciated.

/// NEW CODE:

class Habit {

enum HabitType {
    case health
    case wealth
    case social
    case career
    case noType
}

var habitID: Int
var title: String
var type: HabitType
var duration: Int
var toAccomplish = [String]()
var currentFeelings = [String]()
var howToFix = [String]()

init?(habitID: Int, title: String, type: String, duration: Int, toAccomplish: [String]?, currentFeelings: [String]?, howToFix: [String]?) {

    self.habitID = habitID
    self.title = title
    switch type {
    case "health":
        self.type = HabitType.health
    case "wealth":
        self.type = HabitType.wealth
    case "social":
        self.type = HabitType.social
    case "career":
        self.type = HabitType.career
    default:
        self.type = HabitType.noType
    }
    self.duration = duration

    if let accomplish = toAccomplish {
        self.toAccomplish = accomplish
    }
    if let feelings = currentFeelings {
        self.currentFeelings = feelings
    }
    if let fix = howToFix {
        self.howToFix = fix
    } else {
        return nil
    }
}

}

class MiniHabit: Habit {

var trigger: String
var action: String

init(habitID: Int, title: String, type: String, duration: Int, toAccomplish: [String]?, currentFeelings: [String]?, howToFix: [String]?, trigger: String, action: String) {

    ////init() Error: A non-failable initializer cannot chain to failable initializer 'init(habitID:title:type:duration:toAccomplish:currentFeelings:howToFix:)' written with 'init?' 
    super.init(habitID: habitID, title: title, type: type, duration: duration, toAccomplish: toAccomplish, currentFeelings: currentFeelings, howToFix: howToFix)

    self.trigger = trigger
    self.action = action

}

}


Solution

  • There are to things wrong with your code:

    1. You don't need the required keyword in the initializer. As stated in the documentation:

    Write the required modifier before the definition of a class initializer to indicate that every subclass of the class must implement that initializer

    1. The properties you assign in the superclass' initializer should not be assigned in the subclass

    This code works in a Playground (Xcode 6.3):

    public class Habit {
        var habitID: Int
        var title: String
        var type: String
        var duration: Int
        var toAccomplish = [String]()
        var currentFeelings = [String]()
        var howToFix = [String]()
    
        public init(habitID: Int, title: String, type: String, duration: Int, toAccomplish: [String]?, currentFeelings: [String]?, howToFix: [String]?) {
    
            self.habitID = habitID
            self.title = title
            self.type = type
            self.duration = duration
    
            if toAccomplish != nil {
                self.toAccomplish = toAccomplish!
            }
            if currentFeelings != nil {
                self.currentFeelings = currentFeelings!
            }
            if howToFix != nil {
                self.howToFix = howToFix!
            }
        }
    }
    
    public class MiniHabit: Habit {
        var trigger: String = ""
        var action: String = ""
    
        public init(habitID: Int, title: String, type: String, duration: Int, toAccomplish: [String]?, currentFeelings: [String]?, howToFix: [String]?, trigger: String, action: String) {
            super.init(habitID: habitID, title: title, type: type, duration: duration, toAccomplish: toAccomplish, currentFeelings: currentFeelings, howToFix: howToFix)
    
            self.trigger = trigger
            self.action = action
        }
    }
    
    var h = MiniHabit(habitID: 0, title: "", type: "", duration: 1, toAccomplish: nil, currentFeelings: nil, howToFix: nil, trigger: "", action: "")