swift 中的继承和初始化

Inheritance and initialization in swift

我一直在尝试创建两个不同的 classes:对于 superclass,我使用适当的参数创建我的属性和 init() 函数。但是,当我使用自己的属性和 init() 函数创建 subclass 时,我遇到了麻烦。

我在这里试图实现的是,在我的应用程序中的某个时刻,用户将输入一堆字段,当 he/she 准备好并单击 'ready' 按钮时,字段的内容将用作我的 subclass 的 init() 函数的参数。 superclass的init()比subclass的init()参数少。

我一直在阅读有关指定初始化程序和便利初始化程序的内容,但我有点困惑。也许我真的不需要它们,我不确定。

我试图避免的是在调用 init() 后必须手动更改 subclass 的任何属性的值。

非常感谢任何帮助。

/// 新代码:

class习惯{

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:习惯 {

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

}

}

您的代码有问题:

  1. 您不需要在初始化程序中使用 required 关键字。如 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. 您在超类的初始值设定项中分配的属性不应在子类中分配

此代码适用于 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: "")

我对你的代码做了一些修改,现在是这样的:

// 1.
class Habit {
    var habitID: Int
    var title: String
    var type: String
    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
        self.type = type
        self.duration = duration

        // 2.
        if let acomplish = toAccomplish {
            self.toAccomplish = acomplish
        }

        if let feelings = currentFeelings {
            self.currentFeelings = feelings
        }

        if let fix = howToFix {
            self.howToFix = fix
        }
    }

    class MiniHabit: Habit {
        // 3.
        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) {
            // 4.
            self.trigger = trigger
            self.action = action

            super.init(habitID: habitID, title: title, type: type, duration: duration, toAccomplish: toAccomplish, currentFeelings: currentFeelings, howToFix: howToFix)
        }
    }
}

1.可能不需要将您的class声明为public。来自文档:

Public access enables entities to be used within any source file from their defining module, and also in a source file from another module that imports the defining module. You typically use public access when specifying the public interface to a framework.

默认情况下,您的 classes 将具有 internal 访问权限,如果您不打算从这些 classes 创建框架,这应该没问题。

有关详细信息,请参阅 Swift 编程语言 中的访问控制,link 此处:https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html

2. 使用可选绑定,使用 if let,优于检查可选是否为 nil 然后强制展开它。有关可选绑定的更多信息,请参阅Swift 编程语言

3. triggeraction 不必给空字符串初始值只要你设置它们 before 你调用super init。 Swift 强制在调用 super.init 之前必须初始化当前 class 中定义的所有属性。因为您是在调用 super.init 之前设置它们,所以如果您希望它们不可变,也可以对 triggeraction 使用 let 而不是 var

4. 您现在只初始化 MiniHabit 定义的变量,所有其他变量都由 [=23] 上的指定初始化程序设置=].

此外,我注意到您在 Habit 中有一个 type 变量。如果 type 应该只是 select 几个值,我建议使用 enum,例如:

class Habit {
    enum HabitType {
        // Give these more appropriate names.
        case HabitType1
        case HabitType2
        case HabitType3
    }

    var type: HabitType

    // Other variables...
}

希望对您有所帮助。

响应更新代码的新答案

看起来比上次好多了,但您仍然可以进行一些更改:

首先, 你不需要使用 switch 语句来检查 type 应该是哪个枚举类型。您可以使用将枚举类型作为参数传递给初始化程序。例如,假设这是你的 Habit class:

class Habit {
    enum HabitType {
        case Health
        case Wealth
        case Social
        case Career
    }

    let type: HabitType

    // Don't use a String here, use the HabitType enum.
    init(type: HabitType) {
        self.type = type
    }
}

然后您可以像这样创建一个 Habit 实例:

let aHabit = Habit(type: .Health)

有关详细信息,请参阅Swift编程语言中的枚举

其次, 关于您的 HabitType 枚举,我看到您有一个案例 NoType。这将是使用可选值而不是使用 NoType 的完美位置。例如,您可以将变量 type 声明为可选变量,然后当它等于 nil 时您就知道没有类型。例如,这将是您的 HabitType 枚举:

enum HabitType {
    case Health
    case Wealth
    case Social
    case Career
}

// And this is how could could define type to be optional.
let type: HabitType?

第三, 你在 MiniHabit 的初始化器中遇到的错误是因为你已经声明 Habit 的初始化器是可失败的(在 init 之后用 ? 表示)。在这种情况下这不是必需的,您的初始化程序可能如下所示:

// Not failable anymore. 
init(habitID: Int, title: String, type: String, duration: Int, toAccomplish: [String]?, currentFeelings: [String]?, howToFix: [String]?) {

    // Setup other variables

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

    // No need to return nil if the user didn't supply a value for howToFix.
}

有关可失败初始化程序的更多信息,请参阅此处:https://developer.apple.com/swift/blog/?id=17

希望对您有所帮助!如果还有什么需要澄清的,请告诉我。