Swift 构造器探究
Swift 构造器探究什么时候要用构造器?对于类(Class)其实在其他语言中,比如说Java对于属性的初始化没有严格的要求。甚至在Model层只有对应属性的get,set访问器。而在Swift中无论是对于结构体(Structure)还是类(Class),如果其中存在存储属性(stored property),那么必须在合适的地方给它赋初始值,也就是初始化。不能让它们成为不确定的状态,即没有初始化。关于初始化,Swift提供了两种方式。一种是属性定义的时候初始化,也就是赋默认值。 第二种是在构造器中初始化。 而对于第一种,在Swift中又有两种初始化方式。第一种,是给予明确的值。比如说 而对于第二种初始化方式,更加具体的说,是如果没有是实现第一种初始化方式的时候,必须实现的。也就是说如果你定义一个属性 对于结构体(Structure)Swift中结构体和类的构造器其实差不多。除了结构体中没有析构器(Deinitializer),不能够继承(inherit)以及结构体有memberwise构造器外大体上是一致的。所以你有时候看到一个结构体 构造器的继承designated构造器designated构造器在Swift中很常见,顾名思义这个构造器就是你类中所有构造器的“原型”。在这个构造器中只调用父类的designated构造器或者不调用其他任何构造器称为designated构造器。每个类都必须至少有一个designated构造器,但是你会看到有些情况看不见类中声明designated构造器,那是因为它是一个子类,如果不写任何designated构造器,将会自动继承父类所有designated构造器。我们将在下面的 init(parameters){
// statments
}
convenience构造器convenience构造器是第二种构造器。它主要是横向代理,就是说在convenience构造器中一定存在也只能存在该类的一个构造器通常用 convenience init(parameters){
// 调用该类中的一个构造器
self.init(parameters)
// customize properties
}
类的构造器代理规则
总结下也就说
下面这幅图(引用自苹果官方文档原图)就表明了这两点 下面再来一幅图(引用自苹果官方文档原图) Two-Phase初始化第一阶段类中每个存储属性必须有初始值,一旦每个储值属性的初始状态被确定了,第二阶段就开始了。第二阶段就是在新的实例可用之前对初始值的修改阶段。利用两阶段初始化可以让初始化安全,防止属性值在初始化完成之前被访问,以及属性值被另外的构造器设置为不同的值。这和OC差不多,唯一区别就是OC在第一阶段初始的默认值只能是0或者是nil 初始化有安全检查机制
初始化两个阶段 第一阶段:
下面这幅图是第一阶段 第二阶段:
下面这幅图是第二阶段 构造器的继承和重写Swift和绝大多数面向对象的语言不一样,它不会默认继承所有父类的构造器。也就是说你用类初始化实例的时候,只能访问到该子类构造器(除了自动构造器继承的情况)。这是因为防止用父类的构造方法来创建一个比父类多出一些属性的子类。然而如果调用父类构造方法,就不能初始化子类中的存储属性了,这样就违背了Swift的安全机制。 注意:父类中的构造器在某些特殊情况也会被自动继承,详细内容在后面的自动构造器继承会讲到 如果你在子类中写了一个构造器,并且它与父类某个designated构造器的名字相同,那么你必须用override关键字修饰init构造器。这里还得注意,就算你父类没有任何显式的构造器(但是Swift会默认给你一个 注意:就算你在子类中写的是convenience类型的构造器,如果名字和父类的某个designated构造器,也必须加关键字override修饰。 还有一种情况就是如果你子类中一个构造器的名字和父类的某个convenience构造器相同,又因为父类中的convenience构造器是没办法被子类直接调用的(这个在上面 好吧讲了这么多理论估计你们都晕乎乎的,来讲点实际的例子把。 class Vehicle {
var numberOfWheels = 0
var description: String {
return "(numberOfWheels)wheel(s)"
}
}
这是一个基类。 let vehicle = Vehicle()
println("Vehicle: (vehicle.decription)")
这个时候控制台打印 下面我们来创建一个子类Bicycle class Bicycle: Vehicle{
override init(){
super.init()
numberOfWheels = 2
}
}
由于Bicycle类继承Vehicle类,定义了一个 下面我们来创建Bicycle子类的实例 let bicycle = Bicycle()
println("Bicycle: (bicycle.description)")
控制台打印: 注意:子类可以在合适的位置(具体是什么位置看Two-Phase初始化中介绍)对父类的属性在初始化的时候修改,但是如果属性是常量let声明的,这是不允许的,因为let属性常量一旦被初始化赋值之后,就再也不能改了。 自动构造器继承上面很多地方我们提到了自动构造器继承,那么这东西到底是什么呢?一般情况下,子类如果定义了自己的designated的构造器,父类的构造器是不会被继承的。但是,如果子类没有定义任何自己的构造器,那么子类就会继承父类的构造器。
即使你在子类中添加了其他convenience构造器,这些规则也是适用的。 注意上面所说的提供自定义手动实现,也可以包括子类中用convenience构造器覆盖父类的designated构造器。比如说父类有个 这个是有点抽象,我们来举个例子把 class Food {
var name: String
init(name: String) {
self.name = name
}
convenience init() {
self.name(name: "[Unnamed]")
}
}
这里 现在利用designated构造器创建一个实例 let namedMeat = Food(name: "Bacon")
现在创建了一个实例叫 现在利用convenience构造器创建一个实例 let mysteryMeat = Food()
现在创建了一个实例叫 现在我们创建一个RecipeIngredient类,继承Food类 class RecipseIngredient: Foof { var quantity: Int init(name: String,quantity: Int){ self.quantity = quantity super.init(name: name) // customize superclass properties if needed } override convenience init(name: String) { self.init(name: name,quantity: 1) } }
这里我们定义了RecipeIngredient类,它继承了Food类。其中 构造器继承关系图 接下来我会结合Two-Phase初始化机制来讲解这个RecipeIngredient类的初始化过程。 首先明确的是,RecipeIngredient类只有一个designated构造器叫做init(name: String,quantity: Int)。当这个类初始化实例的时候后,如果使用这个构造器。首先,要满足类的代理规则1,在designated构造器中必须调用最近父类的designated的构造器。但是要先满足安全检查第一个步骤,在调用父类designated构造器之前,必须先初始化改类中定义的所有存储属性。所以对quantity属性进行初始化 现在我们来用不同的构造器创建几个实例 let oneMysteryItem = RecipeIngredient()
let oneBacon = RecipeIngredient(name: "Bacon")
let sixEggs = RecipeIngredient(name: "Eggs",quantity: 6)
现在实例 再来一个更加特殊的类ShopListItem class ShoppingListItem: RecipeIngredient {
var purchased = false
var description: String{
var output = "(quantity)x (name)"
output += purchased ? "√" : "×"
return output
}
}
你可以看到这个类没有任何构造器对 现在我们创建个实例数组 var breakfastList = [
ShoppingListItem(),ShoppingListItem(name: "Bacon"),ShoppingListItem(name: "Eggs",quantity: 6)
]
breakfastList[0].name = "Orange juice"
breakfastList[0].purchased = true
for item in breakfastList {
println(item.decription)
}
控制台输出结果
这里第一个item是ShoppingListItem,它调用的是 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |