初始化是为类 结构体 或者枚举准备实例的过程。这个过程需要给实例里的每一个存储属性设置一个初始值并且在新实例可以使用之前执行任何其它所必需的配置或初始化。

初始化器

初始化器在创建特定类型的实例时被调用。在这个简单的形式中,初始化器就像一个没有形式参数的实例方法,使用 init 关键字来写:

init() {
// perform some initialization here
}

代码示例

struct Fahrenheit {
var temperature:Double init() {
temperature = 2.0;
}
} var f = Fahrenheit()
f.temperature //

默认的属性值

struct Fahrenheit {

    var temperature = 32.0

}

初始化形式参数

struct Celsius {
var temperatureInCelsius:Double init(fromFahrenheit fahrenheit:Double) {
temperatureInCelsius = fahrenheit
}
init(fromKelvin kelvin:Double) {
temperatureInCelsius = kelvin - 273.15
}
} let boilingPointOfWater = Celsius(fromFahrenheit: 212.0) let freezingPointOfWater = Celsius(fromKelvin: 273.15)

可选属性类型

如果你的自定义类型有一个逻辑上是允许无值的存储属性。声明属性为可选类型。可选类型的属性自动地初始化为nil,表示该属性在初始化期间故意的设为还没有值。

class SurveyQuestion {
var text:String
var response:String?
init(text:String) {
self.text = text
}
func ask() {
print(text)
}
} let cheeseQuestion = SurveyQuestion(text: "do you like cheese?")
cheeseQuestion.ask()
cheeseQuestion.response = "Yes,I do like cheese."

对调查问题的回答直到被问的时候才能知道,所以 response 属性被声明为 String? 类型,或者是“可选 Stirng ”。当新的 SurveyQuestion 实例被初始化的时候,它会自动分配一个为 nil 的默认值,意味着“还没有字符串”。

在初始化中分配常量属性

你可以修改上面的SurveyQuestion例子,给text使用常量属性而不是变量属性来表示问题,来明确一旦SurveyQuestion的实例被创建,那个问题将不会被改变。尽管现在的text属性是一个常量。但他依然可以在类的初始化器里设置。

class SurveyQuestion {
let text:String
var response:String?
init(text:String) {
self.text = text
}
func ask() {
print(text)
}
} let cheeseQuestion = SurveyQuestion(text: "how about beets?")
cheeseQuestion.ask()
cheeseQuestion.response = "I also like beets."

默认初始化器

Swift为所有媒体公初始化器的结构体或者类提供了一个默认的初始化器来给所有的属性提供了默认值。这个磨人的初始化器只是简单的创建了一个所有属性都有默认值的新实例。

class shoppingListItem {
var name:String?
var quantity =
var purchased = false
}
var item = shoppingListItem()

结构体类型的成员初始化器

如果结构体类型中没有定义任何自定义初始化器,它会自动获得一个成员初始化器。不同于默认初始化器,结构体会接收成员初始化器即使它的存储属性有默认值。

这个成员初始化器是一个快速初始化新结构体实例成员属性的方式。新实例的属性初始值可以通过名称传递到成员初始化器里

struct Size {
var width = 0.0,height = 0.0
}
let twoByTwo = Size(width: 2.0, height: 2.0)

值类型的初始化器委托

初始化器可以调用其它初始化器来执行部分实例的初始化。这个过程叫做初始化器委托。避免了多个初始化器里冗余代码。

struct Size {
var width = 0.0, height = 0.0
}
struct Point {
var x = 0.0, y = 0.0
} struct Rect {
var origin = Point()
var size = Size()
init() { }
init(origin:Point,size:Size) {
self.origin = origin
self.size = size
}
init(center:Point,size:Size) {
let originX = center.x - (size.width / )
let originY = center.y - (size.height / ) self.init(origin:Point(x: originX, y: originY),size:size)
}
} let originRect = Rect(origin: Point(x: 2.0, y: 2.0),
size: Size(width: 5.0, height: 5.0))
let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
size: Size(width: 3.0, height: 3.0))

类的继承和初始化

class Avatar {
var name:String
var life = { didSet {
if life > {
life =
}
if life <= {
self.isAlive = false
}
}
}
var isAlive:Bool = true
var description:String {
return "I am avatar \(name)"
}
init(name:String) {
self.name = name
}
//便利构造函数
convenience init(firstName:String,secondName:String) {
self.init(name:firstName + secondName)
}
func beAttacked(attack:Int) {
life -= attack
if life <= {
isAlive = false
}
}
} class User:Avatar {
var score =
var level =
var group:String
//重写属性
override var description: String {
return "I am user \(name)"
} func getScore(score:Int) {
self.score += score
if score > level * {
level +=
}
}
//先把子类的所有初始化完成 之后才能调用父类的构造方法
init(name: String,group:String = "") {
//第一阶段 构造实例
self.group = group;
super.init(name: name)
//第二阶段 逻辑判断 self的使用必须在构造完成以后
if group == "" {
self.getScore(score: -)
}
}
//便利构造函数 构造函数中调用了自己的构造函数
convenience init(group: String = "") {
let name = User.generateUserName()
self.init(name:name,group:group)
}
static func generateUserName() ->String {
return "Player" + String(arc4random()%)
}
} class Magician:User {
var magic =
//重写属性
override var description: String {
return "I am magician \(name)"
} func heal(user:User) {
user.life +=
} //构造函数也可以重写
override init(name: String, group: String) {
let defalutGroups = ["Gryffindor","Hufflepuff","Ravenclaw","Slytherin"]
for theGroup in defalutGroups {
if group == theGroup {
super.init(name: name, group: group)
return
}
}
let group = defalutGroups[Int(arc4random()%)]
super.init(name: name, group: group)
}
} final class Warrior:User {
var weapon:String
//重写属性
override var description: String {
return "I am warrior \(name)"
}
//重写方法
override func beAttacked(attack: Int) {
self.life -= attack /
}
//构造函数也可以有默认值
init(name: String, group: String,weapon:String = "Sword") {
self.weapon = weapon super.init(name: name, group: group)
}
} class Monster:Avatar {
func attack(user:User,amount:Int){
user.beAttacked(attack: amount)
}
} final class Zombie:Monster {
var type = "default"
} let user = User(name: "tian", group: "lh")
//多态 一个实例同时属于多个类 就是多态的一种形式 一个方法有不同的响应也是多态的一种形式。在OC中体现为:不同对象对同一消息的不同响应.子类可以重写父类的方法 //因为构造函数有默认值 所以在构造的时候会有两个构造函数
let warrior = Warrior(name: "tian", group: "lh")
warrior.weapon //有一个默认值

构造方法的继承

如果子类实现了父类所有的指定构造函数,难么子类会自动继承父类所有的便利构造函数。上面的例子都有体现。

可失败初始化器

定义类 结构体或者枚举初始化时可以失败在某些情况下可能会很有作用,这个失败可能会有以下几种方式触发。包括传入无效的形式参数值,或者缺少某种外部所需的资源。还有可能是其它阻止初始化的情况。

可失败的初始化器创建了一个初始化类型的可选值。你通过在可失败初始化器写 return nil 语句,来表明可失败初始化器在何种情况下会触发初始化失败。

struct Animal {
let species:String
init?(species:String) {
if species.isEmpty {
return nil
}
self.species = species
}
} if let animal = Animal(species:"") {
animal.species
}else {
print("传入的参数不正确 没被初始化成功")
}

枚举的可失败初始化器

你可以使用一个可失败的初始化器来带一个活着多个形式参数的枚举选择适合的情况。如果提供的形式参数没有匹配到合适的情况初始化器就可能失败。

代码示例

enum TemperatureUnit:Int {
case Kelvin = ,Celsius,Fahrenheit
init?(symbol:Character) {
switch symbol {
case "K":
self = .Kelvin
case "C":
self = .Celsius
case "F":
self = .Fahrenheit
default:
return nil
}
}
} if let temp = TemperatureUnit(symbol:"C") {
temp.rawValue
}else {
print("没有初始化成功")
}

初始化失败的传递

类 结构体 枚举的可失败初始化器可以横向委托到同一个类 结构体或枚举里的另一个可失败初始化器。类似地,子类的可失败初始化器可以向上委托到父类的可失败初始化器。

无论哪种情况,如果你委托到另一个初始化器导致了初始化失败,那么整个初始化过程也会立即失败,并且之后任何初始化代码都不会执行。

class Product {
let name: String
init?(name: String) {
if name.isEmpty { return nil }
self.name = name
}
} class CartItem: Product {
let quantity: Int
init?(name:String, quantity:Int ) {
if quantity < {
return nil
}
self.quantity = quantity
super.init(name: name)
}
} //如果你用不能为空 name 属性和数量为 1 或者更多来创建 CartItem 实例,则初始化成功:
if let twoSocks = CartItem(name: "sock", quantity: ) {
print("Item: \(twoSocks.name), quantity: \(twoSocks.quantity)")
}
//如果你创建了一个 CartItem 实例, quantity 的值为 0 , CartItem 初始化器会导致初始化失败:
if let zeroShirts = CartItem(name: "shirt", quantity: ) {
print("Item: \(zeroShirts.name), quantity: \(zeroShirts.quantity)")
} else {
print("Unable to initialize zero shirts")
} //类似地,如果你尝试创建一个 CartItem 实例,并且令 name 为空值,那么父类 Product 的初始化器就会导致初始化失败:
if let oneUnnamed = CartItem(name: "", quantity: ) {
print("Item: \(oneUnnamed.name), quantity: \(oneUnnamed.quantity)")
} else {
print("Unable to initialize one unnamed product")
}

重写可失败的初始化器

你可以在子类里重写父类的可失败初始化器。就好比其他的初始化器。或者,你可以用子类的非失败初始化器来重写父类的可失败初始化器,这样允许你定义一个初始化不会失败的子类,尽管父类的初始化允许失败。

但是需要注意的是,当你使用子类非失败的初始化器重写了一个可失败的初始化器,向上委托到父类初始化器的唯一方法是强制展开父类可失败初始化器的结果。

class Document {
var name: String? init() {} init?(name: String) {
self.name = name
if name.isEmpty { return nil }
}
} class AutomaticallyNamedDocument: Document {
override init() {
super.init()
self.name = "[Untitled]"
} override init(name:String) {
super.init()
if name.isEmpty {
self.name = "[Untitled]"
}else {
self.name = name
}
}
}

AutomaticallyNamedDocument 类用非可失败的 init(name:) 初始化器重写了父类的可失败 init?(name:) 初始化器。因为 AutomaticallyNamedDocument 类用不同的方式处理了空字符串的情况,它的初始化器不会失败,所以它提供了非可失败初始化器来代替。

必要的初始化器

在类的初始化器前添加required修饰符来表明所有的该类的子类都要实现该初始化器。

class SomeClass {
var name:String
required init(name:String) {
self.name = name
}
} class subClass:SomeClass {
required init(name: String) {
super.init(name: name)
}
}

当子类重写父类的必要初始化器时,必须在子类的初始化器前同样添加 required 修饰符以确保当其它类继承该子类时,该初始化器同为必要初始化器。在重写父类的必要初始化器时,不需要添加 override 修饰符。

通过闭包和函数来设置属性的默认值

class SomeClass {
//这个实际上是一个getter函数
var name:String {
//get {
// return "tianlanlan"
//}
//效果一样
return "tianlanlan" }
//通过闭包设置属性的默认值
var age:Int = {
return
}()
}

上面就是Swift中所有的初始化器的简单介绍。可以看到比OC中要丰富的多。另外Swift中也提供了一种反初始化机制。有点类似于OC中的dealloc方法。

反初始化

在类实例被释放的时候,反初始化器就会被立即调用。可以使用deinit关键字来写反初始化器。

反初始化的原理

当实例不在被需要的时候Swift会自动将其释放掉。以节省资源。代码示例

class Bank {
//静态变量 只有类本身才能调用
static var coinsInBank = 10_000
static func distribute(coins numberOfCoinsRequested: Int) -> Int {
let numberOfCoinsToVend = min(numberOfCoinsRequested, coinsInBank)
coinsInBank -= numberOfCoinsToVend
return numberOfCoinsToVend
}
static func receive(coins: Int) {
coinsInBank += coins
}
} class Player {
var coinsInPurse: Int
init(coins: Int) {
coinsInPurse = Bank.distribute(coins: coins)
}
func win(coins: Int) {
coinsInPurse += Bank.distribute(coins: coins)
}
deinit {
Bank.receive(coins: coinsInPurse)
}
} var playerOne: Player? = Player(coins: )
print("A new player has joined the game with \(playerOne!.coinsInPurse) coins")
// Prints "A new player has joined the game with 100 coins"
print("There are now \(Bank.coinsInBank) coins left in the bank")
//释放掉这个实例
playerOne = nil
Bank.coinsInBank //10000 说明调用了deinit的方法

Swift 学习笔记 (初始化)的更多相关文章

  1. 【swift学习笔记】二.页面转跳数据回传

    上一篇我们介绍了页面转跳:[swift学习笔记]一.页面转跳的条件判断和传值 这一篇说一下如何把数据回传回父页面,如下图所示,这个例子很简单,只是把传过去的数据加上了"回传"两个字 ...

  2. Swift学习笔记(一)搭配环境以及代码运行成功

    原文:Swift学习笔记(一)搭配环境以及代码运行成功 1.Swift是啥? 百度去!度娘告诉你它是苹果最新推出的编程语言,比c,c++,objc要高效简单.能够开发ios,mac相关的app哦!是苹 ...

  3. swift学习笔记5——其它部分(自动引用计数、错误处理、泛型...)

    之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...

  4. swift学习笔记4——扩展、协议

    之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...

  5. swift学习笔记3——类、结构体、枚举

    之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...

  6. swift学习笔记1——基础部分

    之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...

  7. Swift学习笔记一

    最近计划把Swift语言系统学习一下,然后将MagViewer用这种新语言重构一次,并且优化一下,这里记录一下Swift的学习笔记. Swift和Objective-C相比,在语法和书写形式上做了很多 ...

  8. 记录:swift学习笔记1-2

    swift还在不断的更新做细微的调整,都说早起的鸟儿有虫吃,那么我们早点出发吧,趁着国内绝大多数的coder们还没有开始大范围普遍应用. 网上有些大神说:swift很简单!我不同意这个观点,假如你用h ...

  9. swift学习笔记2——函数、闭包

    之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...

随机推荐

  1. NULL的学问

    在数据库中存在一种特殊的值:NULL(空值).一个字段如果没有被赋值,那么它的值就是NULL,NULL并不代表没有值而是表示值未知.员工信息表中存储着身份证号.姓名.年龄等信息,其中某条记录中年龄字段 ...

  2. XCode删除多余的Simulator(模拟器)

    每个xocde都会自带一个模拟器,且都是随安装包一起打包的,比如xcode8.0的就自带iOS10的模拟器,这个是没办法删除. 但是对于想要用iOS10以前的模拟器,可以通过这里进行下载: 最终下载的 ...

  3. 谷歌浏览器chrome设置特定网页使用Https(ssl)访问

    1.在浏览器上输入: chrome://net-internals/ 2.在以下位置输入要自动进行https访问的域名即可. 注意:域名不能用范解析,只能一个一个手动输入.

  4. 苹果放宽了 iOS 5.0 对应用本地存储的限制

    iOS5.0引入了iCloud,让那些需要本地存储较多数据的app开发者(比如支持离线的杂志,新闻类app)陷入了 尴尬的境地,因为将大量数据存储在/Documents 文件夹将导致iCloud同步变 ...

  5. linux远程登录工具

    ssh协议原理

  6. Spark HA模式访问Hadoop HA下的数据

    首先是需要将hadoop的配置文件core-site,xml和hdfs-site.xml 拷贝到Spark conf目录下 然后启动提交即可 spark-submit \ --master spark ...

  7. AutoCAD如何输入文字

    1 运行文字命令(这里使用单行文字),然后鼠标点击文字的起始点,如图所示   2 鼠标分别向上和向右移动一定距离,表示文字的高度(文字的大小)和文字的旋转角度(一般向右,因为是水平文字)   3 最后 ...

  8. struts2类型转换+校验

    1.action中validate()与validateXxx() 用于action执行前的校验,如果校验失败,跳到input视图, 前者校验整个Action: 后者校验该Action中的Xxx方法. ...

  9. vue2.X v-model 指令

    1.v-model指令 <!DOCTYPE html> <html> <head> <title></title> <script s ...

  10. Host is not allowed to connect to this MySQL server解决方案

    创建远程登陆用户并授权 grant all privileges on sakila.* to root@192.168.1.210 identified by '123456'; 123456为ro ...