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
}
}
您的代码有问题:
- 您不需要在初始化程序中使用
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
- 您在超类的初始值设定项中分配的属性不应在子类中分配
此代码适用于 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. trigger
和 action
不必给空字符串初始值只要你设置它们 before 你调用super init。 Swift 强制在调用 super.init
之前必须初始化当前 class 中定义的所有属性。因为您是在调用 super.init
之前设置它们,所以如果您希望它们不可变,也可以对 trigger
和 action
使用 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
希望对您有所帮助!如果还有什么需要澄清的,请告诉我。
我一直在尝试创建两个不同的 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
}
}
您的代码有问题:
- 您不需要在初始化程序中使用
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
- 您在超类的初始值设定项中分配的属性不应在子类中分配
此代码适用于 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. trigger
和 action
不必给空字符串初始值只要你设置它们 before 你调用super init。 Swift 强制在调用 super.init
之前必须初始化当前 class 中定义的所有属性。因为您是在调用 super.init
之前设置它们,所以如果您希望它们不可变,也可以对 trigger
和 action
使用 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
希望对您有所帮助!如果还有什么需要澄清的,请告诉我。