0
votes

I have base class

class Company {
    var list: [Employee] = []
    var name: String = ""
    func getProduct() -> Product {
        return Product(name: "Phone")
    }
    required init(_ list: [Employee], _ name: String) {
        self.list = list
        self.name = name
    }
    convenience init?(_ employee: Employee?, _ name: String) {
        if ( employee == nil || name.isEmpty) { return nil }
        if let emp = employee as? Employee {
             self.init([emp], name)
        }
        self.init(employee, name)
    }
}

And inherited

class FoodCompany: Company{
    var qualityCertificate: String
    required init(_ list: [Employee], _ name: String) {
        self.list = list
        self.name = name
    }
    init? (_ employee : (String?, String?), _ name: String, _ qualityCertificate: String ) {
        if (  employee.0 == nil || employee.1 == nil ) {
            return nil
        }
        if ( name.isEmpty || qualityCertificate.isEmpty) {
            return nil
        }
        self.qualityCertificate = qualityCertificate
        let fName = employee.0 as? String
        let lName = employee.1 as? String
    }
}

In failable init i have an error 'super.init' isn't called on all paths before returning from initializer. But how i can add super.init calling, if i have no data for it? Maybe i don't understand something? Maybe i need to add init without parameters?

2
What do you mean when you say you have no data for it? You have the list and the name that the superclass initializer requires, don't you? And if that's useless data as far as the superclass is concerned, then it sounds like there's no reason for you to use inheritance here. - Noah

2 Answers

2
votes

At the moment you are going to create a subclass of an object you have to call super somewhere.

I don't know what Product and Employee is but to fulfill the inheritage initialization rules you have to write something like this

class Company {
    var list: [Employee] = []
    var name: String = ""
    func getProduct() -> Product {
        return Product(name: "Phone")
    }
    required init(_ list: [Employee], _ name: String) {
        self.list = list
        self.name = name
    }
    convenience init?(_ employee: Employee?, _ name: String) {
        guard let emp = employee, !name.isEmpty else { return nil }
        self.init([emp], name)
    }
}

class FoodCompany: Company {
    var qualityCertificate: String
    required init(_ list: [Employee], _ name: String) {
        self.qualityCertificate = ""
        super.init(list, name)
    }

    init?(_ employee : (String?, String?), _ name: String, _ qualityCertificate: String ) {
        if name.isEmpty || qualityCertificate.isEmpty { return nil }
        guard let fName = employee.0, let nName = employee.1 else { return nil }
        
        self.qualityCertificate = qualityCertificate
        super.init([Employee(fName: fName, nName: nName)], name)
    }
}

Side note: Omitting the parameter labels in init methods is not a good Swift practice.

1
votes

You can call super.init once you have set the properties of the sub-class. So first change the required init in the subclass to

required init(_ list: [Employee], _ name: String) {
    qualityCertificate = ""
    super.init(list, name)
}

Then for the other init I would start by getting the values from the tuple using a guard statement

guard let firstName = employee.0, let lastName = employee.1 else { return nil }

because now we will either have to variables with (non-nil) values that we can use later or the init will return nil

Then we can use those two variables to create an Emplyoee instance and send to super.init

super.init([Employee(firstName, lastName)], name)

If we also add the other validation to the guard statement the full init becomes

init?(_ employee: (String?, String?), _ name: String, _ qualityCertificate: String) {
    guard let firstName = employee.0, let lastName = employee.1, !name.isEmpty, !qualityCertificate.isEmpty) {
        return nil
    }
    self.qualityCertificate = qualityCertificate
    super.init([Employee()], name)
}