Swift 学习

247 阅读8分钟

基础特性

  1. 关于数据类型

    swift 是一种强数据类型,常量和变量必须先声明再使用且须明确类型,不同类型数据不能进行运算,或者需要显式转换,不能将常量与变量进行互转。

    //定义多个同样类型的变量
    var red, green, blue: Double
    
    //随机数
    let ranInt = Int.random(in: 0..<5)
    let ranFloat = Float.random(in: 0.1..<3.2)
    let ranBool = Bool.random()
    
  2. 注释 Swift 的多行注释可以嵌套在其它的多行注释之中

    /* 这是第一个多行注释的开头
    
    /* 这是第二个被嵌套的多行注释 */
    
    这是第一个多行注释的结尾 */
    
  3. 分号

    Swift 并不强制要求你在每条语句的结尾处使用分号(;)但如果同一行内写多条独立的语句,则必须要用分号

  4. 整数 整数就是没有小数部分的数字,比如 42 和 -23 。整数可以是 有符号(正、负、零)或者 无符号(正、零)。比如8位无符号整数类型是 UInt8,32位有符号整数类型是 Int32

    一般来说,你不需要专门指定整数的长度。Swift 提供了一个特殊的整数类型 Int,长度与当前平台的原生字长相同:在32位平台上,Int 和 Int32 长度相同,在64位平台上,Int 和 Int64 长度相同.(UInt 类似)

    let minValue = UInt8.min  // minValue 为 0,是 UInt8 类型
    
    let maxValue = UInt8.max  // maxValue 为 255,是 UInt8 类型
    
  5. 浮点数

    浮点数是有小数部分的数字,浮点数默认推断为Double

    Swift 提供了两种有符号浮点数类型:

    Double 表示64位浮点数, 精确度很高,至少有15位数字

    Float 表示32位浮点数,只有6位数字

    let integerPi = Int(pi)    //integerPi 转为Int 类型
    
    //浮点值转Int时会被截断; 4.75 会变成 4,-3.9 会变成 -3
    
    

注意:结合数字类常量和变量不同于结合数字类字面量。字面量 3 可以直接和字面量 0.14159 相加,因为数字字面量本身没有明确的类型。它们的类型只在编译器需要求值的时候被推测

  1. 类型别名

    类型别名(type aliases)就是给现有类型定义另一个名字。你可以使用 typealias 关键字来定义类型别名

    typealias AudioSample = UInt16
    
    var maxAmplitudeFound = AudioSample.min
    
  2. 布尔值 Swift 有一个基本的布尔(Boolean)类型,叫做 Bool。

    布尔值指逻辑上的值,因为它们只能是真或者假。Swift 有两个布尔常量,true 和 false。 如果你在需要使用 Bool 类型的地方使用了非布尔值,Swift 的类型安全机制会报错。下面的例子会报告一个编译时错误:

    let i = 1
    if i {
        //报错,不会通过编译
    }
    
    
    //布尔取反
    var isSwift = true
    isSwift.toggle()
    
  3. 元组

    元组是一种数据结构,类似于数组或字典,用于定义一组数据

    元组不适合用来创建复杂的数据结构

    let err = (404,"Not Found")
    print(err.0)
    print(err.1)
    
    let error = (errCode:404,errInfo:"Mot Found")
    print(error.errCode)
    print(error.errInfo)
    
    //一个元组的内容可以分解(decompose)成单独的常量和变量
    let (statusCode, statusMessage) = err
    print("The status code is \(statusCode)")
    
    //如果只需要一部分元组值,分解的时候可以把要忽略的部分用下划线(_)标记
    let (justTheStatusCode, _) = http404Error
    print("The status code is \(justTheStatusCode)")
    
    
  4. 可选类型 optionals

    可选类型(optionals)来处理值可能缺失的情况,可选类型表示两种可能: 或者有值, 你可以解析可选类型访问这个值, 或者根本没有值。

    ```
    var str0:Optional<String> = nil
    var str1:String? = nil
    
    不能
    var str2 : string = nil
    
    let possibleNumber = "123"
    let convertedNumber = Int(possibleNumber)
    // convertedNumber 被推测为类型 "Int?", 或者类型 "optional Int"
    
    ```
    

注意:Swift 的 nil 和 Objective-C 中的 nil 并不一样。在 Objective-C 中,nil 是一个指向不存在对象的指针。在 Swift 中,nil 不是指针——它是一个确定的值,用来表示值缺失。任何类型的可选状态都可以被设置为 nil,不只是对象类型。

  1. 解包

    使用 ! 来获取一个不存在的可选值会导致运行时错误。使用 ! 来强制解析值之前,一定要确定可选包含一个非 nil 的值。

    var str1:String? = nil;
    str1 = "hello"
    print(str1)   //输出为:Optional("hello")
    
    
    解包就是取出可选类型的真实值
    print(str1!)  //输出为: hello
    
    
    //如果可选类型为nil,上面解包会报错
    if str1 != nil{
        print(str1!)
    }
    
  2. 可选绑定

    可选绑定(optional binding)来判断可选类型是否包含值,如果包含就把值赋给一个临时常量或者变量。可选绑定可以用在 if 和 while 语句中,这条语句不仅可以用来判断可选类型中是否有值,同时可以将可选类型中的值赋给一个常量或者变量.

     //包含多个可选绑定或多个布尔条件在一个 if 语句中,只要使用逗号分开就行。
     //只要有任意一个可选绑定的值为 nil,或者任意一个布尔条件为 false,
     //则整个 if 条件判断为 false。
     
     var a:Int?
     a = 4
    
     var b:Int?
     b = 42
     print(b)
    
     if let firstNumber  = a,
        let secondNumber = b,
        firstNumber < secondNumber && secondNumber < 100 {
    
          print("\(firstNumber) < \(secondNumber) < 100")
      }
    

基本运算符

Swift 支持大部分标准 C 语言的运算符,且为了减少常见编码错误做了部分改进。如:赋值符(=)不再有返回值,这样就消除了手误将判等运算符(==)写成赋值符导致代码错误的缺陷。同时还提供了 C 语言没有的区间运算符,例如 a..<b 或 a...b,这方便我们表达一个区间内的数值

  1. 空合运算符 ?? 将对可选类型 a 进行空判断,如果 a 包含一个值就进行解包,否则就返回一个默认值 b。

    表达式 a 必须是 Optional 类型。默认值 b 的类型必须要和 a 存储值的类型保持一致。

    let defaultColorName = "red"
    var userDefinedColorName: String?   //默认值为 nil
    
    var colorNameToUse = userDefinedColorName ?? defaultColorName
    
  2. 区间运算符 闭区间运算符(a...b)定义一个包含从 a 到 b(包括 a 和 b)的所有值的区间 半开区间运算符(a..<b)定义一个从 a 到 b 但不包括 b 的区间

字符串和字符

注意:Swift 的 String 类型与 Foundation NSString 类进行了无缝桥接。Foundation 还对 String 进行扩展使其可以访问 NSString 类型中定义的方法。这意味着调用那些 NSString 的方法,你无需进行任何类型转换。

0. 字符串是值类型

在 Swift 中 String 类型是值类型。如果你创建了一个新的字符串,那么当其进行常量、变量赋值操作,或在函数/方法中传递时,会进行值拷贝。在前述任一情况下,都会对已有字符串值创建新副本,并对该新副本而非原始字符串进行传递或赋值操作。

1. 字符串遍历

var emptyString = ""               // 空字符串字面量
var anotherEmptyString = String()  // 初始化方法
var str = "hello"                  // 字面量

for c in str {
    print(c)
}

2. 字符串拼接

let str0 = "w"
let str1 = "p"
let str2 = str0 + str1 + "f"
print(str2)

3. 字符串格式化

let age = 18;
var result = "my age is \(age)"
print(result)

result = String(format: "my age is %ld", age)
print(result);

4. 长字符串

//用三对双引号包括,双引号后不能有其它元素
let str = """
hello w
hello p
hello f
"""
print(str)

5. 字符串访问

字符串长度 count 属性返回的字符数量并不总是与包含相同字符的 NSString 的 length 属性相同。 NSString 的 length 属性是利用 UTF-16 表示的十六位代码单元数字,而不是 Unicode 可扩展的字符群集。

每一个 String 值都有一个关联的索引(index)类型,String.Index,它对应着字符串中的每一个 Character 的位置。不同的字符可能会占用不同数量的内存空间,所以要知道 Character 的确定位置,就必须从 String 开头遍历每一个 Unicode 标量直到结尾。因此,Swift 的字符串不能用整数(integer)做索引。

startIndex 属性可以获取一个 String 的第一个 Character 的索引。 endIndex 属性可以获取最后一个 Character 的后一个位置的索引。 因此,endIndex 属性不能作为一个字符串的有效下标。 如果 String 是空串,startIndex 和 endIndex 是相等的。

let greeting = "Guten Tag!"
greeting[greeting.startIndex]                                   // G

greeting[greeting.index(before: greeting.endIndex)]             // !

greeting[greeting.index(after: greeting.startIndex)]            // u

let index = greeting.index(greeting.startIndex, offsetBy: 7)    // a
greeting[index]

indices 属性会创建一个包含全部索引的范围(Range)

for index in greeting.indices {
   print("\(greeting[index]) ", terminator: "")
}
// 打印输出“G u t e n   T a g ! ”

6. 插入删除

welcome.insert("!", at: welcome.endIndex)                     // "hello!"

welcome.insert(contentsOf:" there", at: welcome.index(before: welcome.endIndex))  
//"hello there!"


welcome.remove(at: welcome.index(before: welcome.endIndex))    //"hello there"


let range = welcome.index(welcome.endIndex, offsetBy: -3)..< welcome.endIndex
welcome.removeSubrange(range)

数组 集合 字典

使用方括号 [] 来创建数组或字典或集合,并使用下标或者键(key)来访问元素

数组

数组中可以是对象或基础数据类型,数组使用有序列表存储同一类型的多个值。

var 代表可变数组 let 表不可变数组

let arr0: Array<Any> = ["wp",18]

var arr1 = ["w","p","f"]

var arr2 = [Double](repeating: 3, count: 3)   //相当于[3,3,3]
var arr3: [Dounble] =  [1.0,2.0]

var arr4 = arr2 + arr3                       //数组拼接

var arr = [String]()                         //空数组
var dic = [Strig: Float]()                   //空字典

1. 数组访问

var arr:[Any] = ["w","p","f"]
//元素个数
print(arr.count)

//判空
if arr.isEmpty {
    print("空")
}else{
    print("非空")
}
//增加元素
arr += ["go"] //元素类型相同才能用合并

arr.append("home")
arr.insert("Speaker", at: 0)
arr.insert("!", at: arr.endIndex)

//删除
arr.remove(at: 0)
arr.removeFirst()
arr.removeLast()
arr.removeAll()

//反转
arr.reverse()

2. 数组遍历

var arr:[Any] = ["w","p","f"]
        
for item in arr {
    print(item);
}

for (index,value) in arr.enumerated() {
    print(index,value)
} 

for item in 0...1 {
    print(item)
}

集合

集合用来存储相同类型并且没有确定顺序的值。当集合元素顺序不重要时或者希望确保每个元素只出现一次时可以使用集合而不是数组。

1. 集合初始化

var letters = Set<Character>()

letters.insert("a")

letters = []

var favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"]

2. 访问修改

//判空
if favoriteGenres.isEmpty {

} else {

}

//插入
favoriteGenres.insert("Jazz")

//删除
//它是该集合的一个元素则删除它并且返回它的值,若该集合不包含它,则返回 nil。
if let removedGenre = favoriteGenres.remove("Rock") {

} else {

}


//转换成数组
favoriteGenres.sorted()

字典

字典是一种无序的集合,它存储的是键值对之间的关系,其所有键的值需要是相同的类型,所有值的类型也需要相同。

1.字典声明及初始化

var dic0:[Int:String] = [1:"w",2:"p"]
var dic1:[String:Any] = [String:Any]()
var dic2:[String : Any] = ["name":"wpf","age":18]

var dic3:Dictionary<key value> = []

var p:[NSString:Any] = ["name":"zhange","age":18,"sex":"男"]
p.removeValue(forKey: "name")
print(p)
        

2. 遍历

for item in dic {
    print(item)
}

for key in dic.keys {
    print(key)
}

for value in dic.values {
    print(value)
}

for (key,value) in dic {
    print(key)
    print(value)
}

控制流

使用 if 和 switch 来进行条件操作,使用 for-in、while 和 repeat-while 来进行循环

switch后可以不跟(),case后可以不跟break,默认不穿透;但break 可以提前结束

如果需要case穿透,则可以使用关键字fallthrough

swift支持多种数据类型

let sex = 0
 
switch sex {
case 0 :
    print("男")
case 1 :
    print("女")
default :
    print("其他")
}
let sex = 0
 
switch sex {
case 0:
    fallthrough
case 1:
    print("正常人")
default:
    print("其他")
}
//浮点型
let f = 3.14
switch f {
case 3.14:
    print("π")
default:
    print("not π")
}

//字符串
let opration = "+" 
switch opration {
    case "+":
        print("+")
    case "-":
        print("-")
    case "*":
        print("*")
    case "/":
        print("/")
default:
    break
}

//区间
let score = 88
switch score {
case 0..<60:
    print("不及格")
case 60..<80:
    print("及格")
case 80..<90:
    print("良好")
case 90..<100:
    print("优秀")
default:
    print("满分")
}

//同时匹配 a A
let anotherCharacter: Character = "a"

switch anotherCharacter {
case "a", "A":
    print("The letter A")
default:
    print("Not the letter A")
}

如果你不需要区间序列内每一项的值,你可以使用下划线_ 替代变量名来忽略这个值

let base = 3
let power = 10
var answer = 1
for _ in 1...power {
    answer *= base
}

switch 也可以匹配元组

let somePoint = (1, 1)
switch somePoint {
case (0, 0):
    print("\(somePoint) is at the origin")
case (_, 0):
    print("\(somePoint) is on the x-axis")
case (0, _):
    print("\(somePoint) is on the y-axis")
case (-2...2, -2...2):
    print("\(somePoint) is inside the box")
default:
    print("\(somePoint) is outside of the box")
}

case 分支允许将匹配的值声明为临时常量或变量,并且在 case 分支体内使用,因为匹配的值在 case 分支体内,与临时的常量或变量绑定

let anotherPoint = (2, 0)

switch anotherPoint {

case (let x, 0):
    print("on the x-axis with an x value of \(x)")
case (0, let y):
    print("on the y-axis with a y value of \(y)")
case let (x, y):
    print("somewhere else at (\(x), \(y))")
}

case 分支的模式可以使用 where 语句来判断额外的条件

let yetAnotherPoint = (1, -1)
switch yetAnotherPoint {
case let (x, y) where x == y:
    print("(\(x), \(y)) is on the line x == y")
case let (x, y) where x == -y:
    print("(\(x), \(y)) is on the line x == -y")
case let (x, y):
    print("(\(x), \(y)) is just some arbitrary point")
}
// 输出

函数

//没有参数,没有返回值
func gotest0() {
    print(#function)
}
func gotest1() -> Void {
    print(#function)
}
//没有参数,有返回值
func gotest2() -> String {
    return String(format: "%@", #function)
 }
//有参数,没有返回值
func gotest3(name:String,age:Int){
    print(#function)
}
//有参数,有返回值
func gotest4(sex:String) -> String {

    return sex
}

1. 默认参数

func add(a:Int,b:Int = 20) -> Int {
    return a + b
}
print(add(a: 1))
print(add(a: 1, b: 2))

2. 可变参数

参数个数可以是可变的(类型相同),其本质就是一个数组参数

func mAdd(a:Int...) -> Int {
      
    var temp = 0
    for n in a {
        temp += n
    }
    return temp
}

mAdd(a: 1,2,3)

3. 引用类型

默认情况下所有参数都是值传递,如果需要改变外部变量需要址传递inout

func swap(a : inout Int, b : inout Int) {
   let temp = a
   a = b
   b = temp
}
 
var a = 10
var b = 20
swap(a: &a, b: &b)
print("a:\(a), b:\(b)")

闭包

闭包是一个特殊函数 //未完