其实在其他语言中,比如说Java对于属性的初始化没有严格的要求。甚至在Model层只有对应属性的get,set访问器。而在Swift中无论是对于结构体(Structure)还是类(Class),如果其中存在存储属性(stored property),那么必须在合适的地方给它赋初始值,也就是初始化。不能让它们成为不确定的状态,即没有初始化。关于初始化,Swift提供了两种方式。一种是属性定义的时候初始化,也就是赋默认值。 第二种是在构造器中初始化。这里做个小结:存储属性必须初始化,初始化的方式且只能在以上两种方式选择,并且至少包含其中一种。
而对于第一种,在Swift中又有两种初始化方式。第一种,是给予明确的值。比如说var name = "Bob"
Swift的数据类型推断机制会自动推断出name
是一个String类型变量,初始值为Bob
。第二种,是Optional类型初始化,通常用在这个属性在程序运行过程中可能存在值也可能不存在值的时候。比如说var avatar: UIImage?
一个人可能没有头像。假设avatar
是Person
类的一个存储属性,程序在运行过程,如果Person
类创建一个实例let myPerson = Person()
, 如果没有给myPerson.avatar
赋值,那么myPerson
中avatar
属性自动初始化为nil
。如果myPerson.avatar = UIImage(named: "prettyGirl")
,那么avatar属性初始化就是UIImage(named: "prettyGirl")
。
而对于第二种初始化方式,更加具体的说,是如果没有是实现第一种初始化方式的时候,必须实现的。也就是说如果你定义一个属性var avatar: UIImage
既没有给予明确的初始值,也没有让它成为Optional类型,那么必须实现在构造器中的初始化。这就是什么时候要用构造器的重点了。
然而Swift的构造器又有两种,一种是designated构造器,一种是convenience构造器。所有designated构造器都必须初始化那些没有满足第一种情况的存储属性。注意这里是类中所有的designated构造器都必须要做这件事。具体怎么做请看后文Designated构造器
Swift中结构体和类的构造器其实差不多。除了结构体中没有析构器(Deinitializer),不能够继承(inherit)以及结构体有memberwise构造器外大体上是一致的。所以你有时候看到一个结构体struct Point
有两个存储属性var x: Double
, var y: Double
,却没有任何构造器,但是他们既不符合类中讨论的第一种初始化方法(即赋默认值)。那么它们违背了语法规则吗?其实不是的,如果结构体没有自定义的构造器,Swift隐式创建了一个init(x:y:)
的构造器其内容就相当于self.x = x, self.y = y
。如果你手动给结构体加个空内容的构造器init(){ }
,编译器就报Return from initializer without initializing all stored properties
的错误。也就是说,如果你创建了你自己定义的构造器,Swift就默默地帮你把memberwise构造器去掉了,而你自己定义的构造器又没有对存储属性初始化,那么这违背了语法规则。但是如果你想同时拥有这两个构造器(memberwise构造器和自定义构造器),你可以把自定义的构造写到Extension Point{ // custom initializer }
里面进去。
designated构造器在Swift中很常见,顾名思义这个构造器就是你类中所有构造器的“原型”。在这个构造器中只调用父类的designated构造器或者不调用其他任何构造器称为designated构造器。每个类都必须至少有一个designated构造器,但是你会看到有些情况看不见类中声明designated构造器,那是因为它是一个子类,如果不写任何designated构造器,将会自动继承父类所有designated构造器。我们将在下面的自动构造器继承
中详细讲到。
init(parameters){
// statments
}
convenience构造器是第二种构造器。它主要是横向代理,就是说在convenience构造器中一定存在也只能存在该类的一个构造器通常用self.init(parameters)
调用该类的一个构造器。当然convenience构造器不是必要的。
convenience init(parameters){
// 调用该类中的一个构造器
self.init(parameters)
// customize properties
}
总结下也就说
下面这幅图(引用自苹果官方文档原图)就表明了这两点
SubClass的convenience构造器调用了第二个designated构造器(符合规则2),第二个designated的调用了SuperClass的designated构造器(符合规则1),这表明了convenience构造器最终调用的是designatedg构造器(符合规则3)。同理其他的构造器调用亦是如此
下面再来一幅图(引用自苹果官方文档原图)
第一阶段类中每个存储属性必须有初始值,一旦每个储值属性的初始状态被确定了,第二阶段就开始了。第二阶段就是在新的实例可用之前对初始值的修改阶段。利用两阶段初始化可以让初始化安全,防止属性值在初始化完成之前被访问,以及属性值被另外的构造器设置为不同的值。这和OC差不多,唯一区别就是OC在第一阶段初始的默认值只能是0或者是nil
初始化有安全检查机制
self
知道第一阶段初始化结束初始化两个阶段
第一阶段:
下面这幅图是第一阶段
第二阶段:
下面这幅图是第二阶段
原文地址:http://blog.csdn.net/qq_19762007/article/details/45232969