Fork me on GitHub

Swift3.0基础

1,注意点

  • 编写代码的时候,一定要养成良好的编程习惯,该有空格的时候一定要有,不该有空格的时候一定不要有(不然可能会报错)

2,基础类型转字符串

1
2
1, String(width)
2, "\(20)"

3,字典

  • ①初始化方法

    1
    2
    //初始化字典
    var ageDict = [String:Any]()
  • ②错误1,字典中既有字符串,又有整型。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    //错误示例
    var occupations = [
    "Malcolm" : "Captain",
    "age": 12
    ]//这里也不能用@12
    ---
    ✅ 解决方式1,结尾添加as [String : Any]
    var occupations = [
    "name" : "Mr.han",
    "age" : 12
    ] as [String : Any]

4,数组

  • ①数组初始化方法

    1
    2
    3
    4
    5
    6
    7
    //初始化数组(可以添加任意类型)
    var shoppingList = [Any]()
    //初始化一个Int类型的数组
    var array2:[Int] = [Int]()
    //这种应该不会有人用吧
    var array1:[Int] = [Any]() as! [Int]
  • ②数组和元组的区别

    1
    2
    3
    4
    5
    6
    7
    //区别一
    1,数组[1,2,3,4,5]
    2,元组(1,2,3,4,5)
    //区别二(取值)
    数组array[0]
    元组array.0

5,控制流

1
2
3
4
5
/*
控制流
1,使用if和switch来进行条件操作,使用for-in、for、while和repeat-while来进行循环
注:包裹条件和循环变量可以省略,但是语句体的大括号是必须的。
*/
  • ① for in

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    /*
    1,使用for-in 来遍历字典,需要两个变量来表示每个键值对。(kind和numbers)
    2,字典是一个无序的集合,所以他们的键和值一任意顺序迭代结束
    */
    let intestingNumbers = [
    "counts1" : [1,2,3,4],
    "counts2" : [5,6,7,8],
    "counts3" : [9,10,11,12],
    ]
    //从输出可以看出字典输出是无序的
    intestingNumbers
    for (kind,numbers) in intestingNumbers {
    //只是单纯的输出kind和numbers,那么将展示最后一个键值对
    // kind
    // numbers
    // print(kind)
    // print(numbers)
    }
  • ② while和repeat-while

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    /*
    1,while来重复执行一段代码知道不满足条件
    2,repeat-while至少执行一次(替代do-while)
    */
    var n = 2
    while n<100 {
    n = n * 2
    }
    //print(n) //128
    repeat{
    n = n * 2
    }while n<100
    //print(n) //256
    /*
    在循环中使用
    ..< 表示范围(左闭右开)
    ... 表示范围(左闭右闭)
    */
    var total = 0
    for i in 0...4 {
    total += i
    }
    total
  • ③ switch用法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    /*
    >1,switch支持任意类型的数据以及各种比较操作--不仅仅是整数以及测试相等
    >2,fallthrough:满足一个条件后,继续判断后面的条件时,在满足的条件后面添加fallthrough
    注意使用fallthrough,下面的case条件不能为下面这种形式,case let x where x.hasPrefix("red"):
    不然报错(error: 'fallthrough' cannot transfer control to a case label that declares variables)
    >3,如果满足了条件,不执行任何操作,不能什么都不写,会报错。
    可以添加“空语句”
    →1, break
    →2, () //旧版本为():
    */
    let vegetable = "red pepper"
    switch vegetable {
    case "celery":
    print("hehe")
    case "red pepper":
    print("good")
    fallthrough //下一个case,不能使用下面的形式。
    // case let x where x.hasPrefix("red"):
    // print("This is")
    default:
    // print("sorry")
    () //空语句
    }

6,值缺失

  • ① ?的用法(值缺失)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var optionalName:String? = "Mr.han"
    if optionalName != nil {
    optionalName //之前好像不能在这里调用optionalName,采用的是下面的方式调用。
    }
    if let pName = optionalName { //这里我们可以再声明一个变量来接收optionalName
    pName
    optionalName
    }
  • ② ??的用法(如果值缺失,使用默认值代替)

    1
    2
    3
    let nickName:String? = nil
    let fullName:String = "mrhan"
    let infomalGreeting = "Hi \(nickName ?? fullName)" //如果nickName缺失的话,那么fullName就会替代它

7,函数

1
2
1,使用func来声明一个函数,使用函数名和参数名来调用函数。
2,使用->来指定函数返回值的类型
  • 示例1

    1
    2
    3
    4
    5
    func greet(name:String, day:String) -> String{
    return "Hello \(name), today is \(day)"
    }
    greet(name: "mrhan", day: "12.14")
  • 示例2

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    /*②
    1, 使用元组来让一个函数返回多个值。取值时该元组的元素可以用名称或者数字来表示。
    注意:如果返回值写成[Int],return的时候,写成return [min,max,sum]
    2,由1可知,数组和元组的区别
    →1,括号 (中括号 和 括号)
    →2,取值(array[0] 和 array.0)
    */
    func calculate(scores:[Int]) -> (min:Int, max:Int, sum:Int){
    var min = scores[0]
    var max = scores[0]
    var sum = 0
    scores[0]
    for score in scores{
    if min > score{
    min = score
    }else if max < score{
    max = score
    }
    sum += score
    }
    return (min,max,sum)
    }
  • 示例3

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    /*③
    函数可以带有可变个数的参数,这些参数在函数内表现为数组的形式,但是不能直接传数组。
    */
    func sumOf(numbers:Int...) -> Int{
    var sum = 0
    for number in numbers {
    sum += number
    }
    return sum
    }
    sumOf(numbers: 1,2,3) //这里不能传数组
  • 示例4

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    /*④
    函数可以嵌套,被嵌套的函数可以访问外侧函数的变量(比如重构一个太长或复杂的函数)
    */
    func returnFifteen() -> Int{
    var y = 10
    func add(){
    y += 5
    }
    add()
    return y
    }
    returnFifteen()
  • 示例5

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    /*⑤
    函数是第一等类型,这意味着函数可以作为另一个函数的返回值
    解析:((Int) -> Int)
    1,第一个(Int)表示的是addOne传入的参数,而且必须要加括号
    2,第二个Int表示addOne返回值Int
    结论:可以使用一个函数的参数和返回值表示一个函数
    */
    func makeIncrementer() -> ((Int) -> Int){ //这里第一个Int必须带括号,
    func addOne(number:Int) -> Int{
    return 1 + number
    }
    return addOne
    }
    var increment = makeIncrementer()
    increment(7)
  • 示例6

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    /*⑥
    函数也可以当做参数传入另一个函数,注意只传函数名,不需要传参数。
    体会下⑤中的结论:可以使用一个函数的参数和返回值表示一个函数
    */
    func hasAnyMatches(list:[Int], condition:(Int) -> Bool) -> Bool{
    for item in list{
    if condition(item) {
    return true //只要有一个满足就为true
    }
    }
    return false
    }
    func lessThanTen(number:Int) -> Bool{
    return number < 10
    }
    var numbers = [20,19,7,12]
    hasAnyMatches(list: numbers, condition: lessThanTen)

8,闭包

  • Swift闭包
    Swift闭包
    概念:闭包(Closures)是自包含的功能代码块,可以在代码中使用或者用来作为参数传值。
    Swift中的闭包与c和oc中的代码块(blocks)以及其他一些编程语言中的匿名函数比较相似。
    全局函数和嵌套函数其实就是特殊的闭包
  • 闭包的形式有:

    1,全局函数:有名字但不能捕获任何值。
    2,嵌套函数:有名字,也能捕获封闭函数内的值。
    3,闭包表达式:无名闭包,使用轻量级语法,可以根据上下文环境捕获值。
  • Swift中的闭包有很多优化的地方:

    1,根据上下文推断参数和返回值的类型
    2,从单行表达式闭包中隐式返回(也就是闭包体中只有一行代码,可以省略return)
    3,可以使用简化参数名,如$0,$1(从0开始,表示第i个参数…)
    4,提供了尾随闭包语法(Trailing closure syntax)
  • 语法:
    • 1,以下定义了一个接收参数并返回指定类型的闭包语法:(闭包语法即闭包公式,所有闭包都套用公式。)
      {
         (parameters) -> return type in
         statements
      }
    • 2,以闭包形式接收两个参数并返回布尔值:
      {
         (Int, Int) -> Bool in
         Statement1
         …
      }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/*①
sorted方法
Swift标准库提供了名为sorted(by:)的方法,会根据您提供的用于排序的闭包函数将已知类型数组中的值进行排序。
排序完成后,sorted(by:)方法会返回一个与原数组大小相同,包含同类型元素且元素已正确排序的新数组。原数组的值不变。
*/
let names = ["AT", "AE", "D", "S", "BE"]
func backwards(s1:String, s2:String) -> Bool{
return s1 > s2
}
var resulet = names.sorted(by: backwards)
/*②
参数名称缩写:
Swift自动为内联函数提供了参数名称缩写功能,您可以直接通过$0,$1,$2来顺序调用闭包的参数。
$0和$1表示闭包中第一个和第二个String类型的参数
如果你在闭包表达式中使用参数名称缩写,您可以在闭包参数列表中省略对其定义,并且对应参数名称缩写的类型会通过函数类型进行推断。in关键字也可以被省略。
*/
var st = names.sorted(by: { $0 > $1 })
/*③
运算符函数
Swift 的String类型定义了关于大于号 (>) 的字符串实现,其作为一个函数接受两个String类型的参数并返回Bool类型的值。 而这正好与sort(_:)方法的第二个参数需要的函数类型相符合。
因此,您可以简单地传递一个大于号,Swift可以自动推断出您想使用大于号的字符串函数实现排序。
*/
var st2 = names.sorted(by: >)
/*
尾随闭包:
尾随闭包是一个书写在函数括号之后的闭包表达式,函数支持将其作为最后一个参数调用。
sorted()后面的{ $0 > $1 }为尾随闭包
注意:
如果函数只需要闭包表达式一个参数,当您使用尾随闭包时,您甚至可以把()省略掉。
所以也可以写成
var reversed = names.sorted{ $0 > $1 }
*/
let names2 = ["AT", "AE", "D", "S", "BE"]
var reversed = names.sorted(){ $0 > $1 } //也可以省略()
reversed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/*
捕获值
闭包可以在其定义的上下文中捕获常量或变量。
Swift最简单的闭包形式是嵌套函数,也就是定义在其他函数的函数体内的函数。
嵌套函数可以捕获其外部函数所有的参数以及定义的常量和变量。
注意:这里的one1的作用是替代参数名one
*/
func makeAdd(one1 one:Int) -> (() -> Int){
var amount = 0
func incrementor() -> Int{
amount += one
return amount
}
return incrementor
}
let incrementByTen = makeAdd(one1: 10) //此时没有调用闭包中的函数体
incrementByTen() //10
incrementByTen() //20
/*
闭包是引用类型
1,上个例子中,incrementByTen是常量,但是这些常量指向的闭包仍然可以增加其捕获的变量值。
2,这是因为函数和闭包都是引用类型。
3,无论您将函数/闭包赋值给一个常量还是变量,您实际上都是将常量/变量的值设置为对应函数/闭包的引用。
4,如果您将闭包赋值给了两个不同的常量/变量,两个值都会指向同一个闭包
*/
var incrementByTen2 = incrementByTen
incrementByTen2() //30
//传参数,并直接调用闭包。
makeAdd(one1: 10)()
makeAdd(one1: 20)()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/*
逃逸闭包:
当一个闭包作为参数传到一个函数中,但是这个闭包在函数返回之后才被执行,我们称该闭包从函数中逃逸。
当你定义接受闭包作为参数的函数时,你可以在参数名之前标注@escaping,用来指明这个闭包是允许"逃逸"出这个函数的。
可以理解为:一种能使闭包"逃逸"出函数的方法是,将这个闭包保存在一个函数外部定义的变量中。(比如异步操作成功后回调)
*/
var completionHandlers: [() -> Void] = [] //定义一个变量用来存储闭包
/*
逃逸闭包(意味着需要显式的调用self)
someFunctionWithEscapingClosure(_:) 函数接受一个闭包作为参数,该闭包被添加到一个函数外定义的数组中。
如果你不将这个参数标记为 @escaping,就会得到一个编译错误。
注意:逃逸闭包和非逃逸闭包操作的变量x是两个值
*/
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
print("nimeide")
//把闭包存储到变量completionHandlers(数组)中
completionHandlers.append(completionHandler) //只有逃逸闭包才可以添加到completionHandlers中
// completionHandler() //也可以在这里直接调用
}
/*
非逃逸闭包(意味着可以隐式的引用self)
*/
func someFunctionWithNonescapingClosure(closure: () -> Void) {
closure()
}
class SomeClass {
var x = 10
func doSomething() {
//闭包实现
someFunctionWithEscapingClosure { self.x = 100 } //
someFunctionWithEscapingClosure { self.x = 300 }
someFunctionWithNonescapingClosure { x = 200 } //也可以用self.x
}
}
let instance = SomeClass()
instance.doSomething()
print(instance.x)// 打印出 "200"
completionHandlers.count
completionHandlers.last!() //这里的?也可以换成! //作用:确保闭包存在时,再执行()
print(instance.x)// 打印出 "300",而不是200,逃逸闭包和非逃逸闭包不是同一个变量。