Swift官方文档阅读笔记(函数、闭包、枚举、类和结构体、属性、方法、初始化)

Swift中文文档连接

函数相关

可变形式参数

一个可变形式参数可以接受零或者多个特定类型的值。当调用函数的时候你可以利用可变形式参数来声明形式参数可以被传入值的数量是可变的。可以通过在形式参数的类型名称后边插入三个点符号( ...)来书写可变形式参数。

传入到可变参数中的值在函数的主体中被当作是对应类型的数组。举个栗子,一个可变参数的名字是 numbers类型是 Double...在函数的主体中它会被当作名字是 numbers 类型是 [Double]的常量数组。

下面的栗子计算了一组任意长度的数字的算术平均值(也叫做平均数)。

  func arithmeticMean(_ numbers: Double...) -> Double {
    var total: Double = 0
    for number in numbers {
        total += number
    }
    return total / Double(numbers.count)
}
arithmeticMean(1, 2, 3, 4, 5)
// returns 3.0, which is the arithmetic mean of these five numbers
arithmeticMean(3, 8.25, 18.75)
// returns 10.0, which is the arithmetic mean of these three numbers

注意
一个函数最多只能有一个可变形式参数。

输入输出形式参数

就像上面描述的,可变形式参数只能在函数的内部做改变。如果你想函数能够修改一个形式参数的值,而且你想这些改变在函数结束之后依然生效,那么就需要将形式参数定义为输入输出形式参数。

在形式参数定义开始的时候在前边添加一个 inout关键字可以定义一个输入输出形式参数。输入输出形式参数有一个能输入给函数的值,函数能对其进行修改,还能输出到函数外边替换原来的值。

你只能把变量作为输入输出形式参数的实际参数。你不能用常量或者字面量作为实际参数,因为常量和字面量不能修改。在将变量作为实际参数传递给输入输出形式参数的时候,直接在它前边添加一个和符号 ( &) 来明确可以被函数修改。

注意

输入输出形式参数不能有默认值,可变形式参数不能标记为 inout,如果你给一个形式参数标记了 inout,那么它们也不能标记 var和 let了。

这里有一个 swapTwoInts(::)函数,它有两个输入输出整数形式参数 a和 b:

func swapTwoInts(_ a: inout Int, _ b: inout Int) {
    let temporaryA = a
    a = b
    b = temporaryA
}

函数 swapTwoInts(::)只是简单的将 b和 a的值进行了调换。函数将 a的值储存在临时常量 temporaryA中,将 b的值赋给 a,然后再将 temporaryA的值赋给 b。

你可以通过两个 Int类型的变量来调用函数 swapTwoInts(::)去调换它们两个的值,需要注意的是 someInt的值和 anotherInt的值在传入函数 swapTwoInts(::)时都添加了和符号。

var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
// prints "someInt is now 107, and anotherInt is now 3"

上边的栗子显示了 someInt 和 anotherInt的原始值即使是在函数的外部定义的,也可被函数 swapTwoInts(::)修改。

注意

输入输出形式参数与函数的返回值不同。上边的 swapTwoInts没有定义返回类型和返回值,但它仍然能修改 someInt和 anotherInt的值。输入输出形式参数是函数能影响到函数范围外的另一种替代方式。


闭包相关

涉及关键字:尾随闭包,逃逸闭包 @escaping,自动闭包 @autoclosure 闭包是引用类型
https://www.cnswift.org/closures


枚举相关

关联值

有时将其它类型的关联值与这些成员值一起存储是很有用的。这样你就可以将额外的自定义信息和成员值一起储存,并且允许你在代码中使用每次调用这个成员时都能使用它。
你可以定义 Swift 枚举来存储任意给定类型的关联值,如果需要的话不同枚举成员关联值的类型可以不同。
在Moya里面的使用场景
例如:

enum Barcode {
    case upc(Int, Int, Int, Int)
    case qrCode(String)
}

这可以读作:
“定义一个叫做 Barcode的枚举类型,它要么用 (Int, Int, Int, Int)类型的关联值获取 upc 值,要么用 String 类型的关联值获取一个 qrCode的值。”

递归枚举

关键字:indirect

示例:

indirect enum ArithmeticExpression {
    case number(Int)
    case addition(ArithmeticExpression, ArithmeticExpression)
    case multiplication(ArithmeticExpression, ArithmeticExpression)
}

let five = ArithmeticExpression.number(5)
let four = ArithmeticExpression.number(4)
let sum = ArithmeticExpression.addition(five, four)
let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))

类和结构体

类与结构体的对比

在 Swift 中类和结构体有很多共同之处,它们都能:

  • 定义属性用来存储值;
  • 定义方法用于提供功能;
  • 定义下标脚本用来允许使用下标语法访问值;
  • 定义初始化器用于初始化状态;
  • 可以被扩展来默认所没有的功能;
  • 遵循协议来针对特定类型提供标准功能。

类有而结构体没有的额外功能:

  • 继承允许一个类继承另一个类的特征;
  • 类型转换允许你在运行检查和解释一个类实例的类型;
  • 反初始化器允许一个类实例释放任何其所被分配的资源;
  • 引用计数允许不止一个对类实例的引用。

注意

结构体在你的代码中通过复制来传递,并且并不会使用引用计数。

结构体和枚举是值类型

值类型是一种当它被指定到常量或者变量,或者被传递给函数时会被拷贝的类型。

let hd = Resolution(width: 1920, height: 1080)
var cinema = hd
cinema.width = 2048
println("cinema is now \(cinema.width) pixels wide")
  //println "cinema is now 2048 pixels wide"
print("hd is still \(hd.width) pixels wide")
// prints "hd is still 1920 pixels wide"

类是引用类型

类和结构体之间的选择

按照通用准则,当符合以下一条或多条情形时应考虑创建一个结构体:

  • 结构体的主要目的是为了封装一些相关的简单数据值;
  • 当你在赋予或者传递结构实例时,有理由需要封装的数据值被拷贝而不是引用;
  • 任何存储在结构体中的属性是值类型,也将被拷贝而不是被引用;
  • 结构体不需要从一个已存在类型继承属性或者行为。

合适的结构体候选者包括:

  • 几何形状的大小,可能封装了一个 width属性和 height属性,两者都为 double类型;
  • 一定范围的路径,可能封装了一个 start属性和 length属性,两者为 Int类型;
  • 三维坐标系的一个点,可能封装了 x , y 和 z属性,他们都是 double类型。

属性

注意

  • 如果被标记为 lazy 修饰符的属性同时被多个线程访问并且属性还没有被初始化,则无法保证属性只初始化一次。
  • 全局常量和变量永远是延迟计算的,与延迟存储属性有着相同的行为。不同于延迟存储属性,全局常量和变量不需要标记 lazy 修饰符。

方法

在实例方法中修改值类型

关键字:mutating

    var x = 0.0, y = 0.0
    mutating func moveBy(x deltaX: Double, y deltaY: Double) {
        x += deltaX
        y += deltaY
    }
}
var somePoint = Point(x: 1.0, y: 1.0)
somePoint.moveBy(x: 2.0, y: 3.0)
print("The point is now at (\(somePoint.x), \(somePoint.y))")
// prints "The point is now at (3.0, 4.0)"

//你不能在常量结构体类型里调用异变方法,因为自身属性不能被改变,就算它们是变量属性:
let fixedPoint = Point(x: 3.0, y: 3.0)
fixedPoint.moveBy(x: 2.0, y: 3.0)
// this will report an error

在异变方法里指定自身

异变方法可以指定整个实例给隐含的 self属性。上文中那个 Point的栗子可以用下边的代码代替:

struct Point {
    var x = 0.0, y = 0.0
    mutating func moveBy(x deltaX: Double, y deltaY: Double) {
        self = Point(x: x + deltaX, y: y + deltaY)
    }
}

初始化

类类型的初始化器委托

为了简化指定和便捷初始化器之间的调用关系,Swift 在初始化器之间的委托调用有下面的三个规则:

  • 指定初始化器必须从它的直系父类调用指定初始化器。

  • 便捷初始化器必须从相同的类里调用另一个初始化器。

  • 便捷初始化器最终必须调用一个指定初始化器。

简单记忆的这些规则的方法如下:

  • 指定初始化器必须总是向上委托。
  • 便捷初始化器必须总是横向委托。


    initializerDelegation01_2x.png

两段式初始化

Swift 的类初始化是一个两段式过程。在第一个阶段,每一个存储属性被引入类为分配了一个初始值。一旦每个存储属性的初始状态被确定,第二个阶段就开始了,每个类都有机会在新的实例准备使用之前来定制它的存储属性。

两段式初始化过程的使用让初始化更加安全,同时在每个类的层级结构给与了完备的灵活性。两段式初始化过程可以防止属性值在初始化之前被访问,还可以防止属性值被另一个初始化器意外地赋予不同的值。

注意

Swift 的两段式初始化过程与 Objective-C 的初始化类似。主要的不同点是在第一阶段,Objective-C 为每一个属性分配零或空值(例如 0 或 nil )。Swift 的初始化流程更加灵活,它允许你设置自定义的初始值,并可以自如应对 0 或 nil 不为合法值的情况。

Swift编译器执行四种有效的安全检查来确保两段式初始化过程能够顺利完成:

安全检查 1

指定初始化器必须保证在向上委托给父类初始化器之前,其所在类引入的所有属性都要初始化完成。

如上所述,一个对象的内存只有在其所有储存型属性确定之后才能完全初始化。为了满足这一规则,指定初始化器必须保证它自己的属性在它上交委托之前先完成初始化。

安全检查 2

指定初始化器必须先向上委托父类初始化器,然后才能为继承的属性设置新值。如果不这样做,指定初始化器赋予的新值将被父类中的初始化器所覆盖。

安全检查 3

便捷初始化器必须先委托同类中的其它初始化器,然后再为任意属性赋新值(包括同类里定义的属性)。如果没这么做,便捷构初始化器赋予的新值将被自己类中其它指定初始化器所覆盖。

安全检查 4

初始化器在第一阶段初始化完成之前,不能调用任何实例方法、不能读取任何实例属性的值,也不能引用 self 作为值。

直到第一阶段结束类实例才完全合法。属性只能被读取,方法也只能被调用,直到第一阶段结束的时候,这个类实例才被看做是合法的。

以下是两段初始化过程,基于上述四种检查的流程:

阶段 1
  • 指定或便捷初始化器在类中被调用;
  • 为这个类的新实例分配内存。内存还没有被初始化;
  • 这个类的指定初始化器确保所有由此类引入的存储属性都有一个值。现在这些存储属性的内存被初始化了;
  • 指定初始化器上交父类的初始化器为其存储属性执行相同的任务;
    *这个调用父类初始化器的过程将沿着初始化器链一直向上进行,直到到达初始化器链的最顶部;
  • 一旦达了初始化器链的最顶部,在链顶部的类确保所有的存储属性都有一个值,此实例的内存被认为完全初始化了,此时第一阶段完成。
阶段 2
  • 从顶部初始化器往下,链中的每一个指定初始化器都有机会进一步定制实例。初始化器现在能够访问 self 并且可以修改它的属性,调用它的实例方法等等;
  • 最终,链中任何便捷初始化器都有机会定制实例以及使用 slef 。

自动初始化器的继承

子类默认不会继承父类初始化器。总之,在特定的情况下父类初始化器是可以被自动继承的。实际上,这意味着在许多场景中你不必重写父类初始化器,只要可以安全操作,你就可以毫不费力地继承父类的初始化器。

假设你为你子类引入的任何新的属性都提供了默认值,请遵守以下2个规则:

规则1

  • 如果你的子类没有定义任何指定初始化器,它会自动继承父类所有的指定初始化器。

规则2

  • 如果你的子类提供了所有父类指定初始化器的实现——要么是通过规则1继承来的,要么通过在定义中提供自定义实现的——那么它自动继承所有的父类便捷初始化器。

就算你的子类添加了更多的便捷初始化器,这些规则仍然适用。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容

  • 这是16年5月份编辑的一份比较杂乱适合自己观看的学习记录文档,今天18年5月份再次想写文章,发现简书还为我保存起的...
    Jenaral阅读 2,727评论 2 9
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,580评论 18 139
  • 官方文档 初始化 Initialization是为准备使用类,结构体或者枚举实例的一个过程。这个过程涉及了在实例里...
    hrscy阅读 1,132评论 0 1
  • 1.1绪论 考试流程 打分方式 *E-rater(Structure,Grammar,etc.)*2-4 Huma...
    大屈子_59ec阅读 269评论 0 0
  • 今天第一次发文到简书,其实发的没啥内容,就是还有一百天就考研了,也总想来个考研百天倒计时。 我高考一百天的...
    毛科科阅读 206评论 1 0