美文网首页
[iOS] Swift学习文档 - 白猫版

[iOS] Swift学习文档 - 白猫版

作者: objcat | 来源:发表于2022-01-13 17:23 被阅读0次

    🌈 简介

    Swift 是一种支持多编程范式和编译式的开源编程语言,苹果于2014年WWDC(苹果开发者大会)发布, 用于开发 iOS, OS X 和 watchOS 应用程序。

    Swift 结合了 C 和 Objective-C 的优点并且不受 C 兼容性的限制。

    Swift 在 Mac OS 和 iOS 平台可以和 Object-C 使用相同的运行环境。

    2015年6月8日, 苹果于WWDC 2015上宣布, Swift将开放源代码, 包括编译器和标准库。

    🍎 环境搭建

    电脑:

    MacOS

    官方网站

    https://developer.apple.com

    IDE

    Xcode - 直接在AppStore里面搜索并下载

    🍎 Hello World

    print("Hello world!")
    

    🍎 变量

    // 整型
    var a = 100
    // 浮点型
    var b = 1000.0
    // 字符串
    var c = "Objcat"
    // 数组
    var d = [1, 2, 3]
    // 字典
    let e = ["name": "objcat", "age": "18"]
    // 元组
    let f = (1, 2, 3)
    let g = (name: "张三", age: "16")
    
    var 表示变量 let 表示常量
    

    🍎 函数

    🌲 无参数无返回值

    func hello() {
        print("hello world!")
    }
    

    🌲 有参数无返回值

    func hello(text: String) {
        print(text)
    }
    
    hello(text: "hello world!")
    

    🌲 有参数有返回值

    func hello(text: String) -> String {
        return text
    }
    
    var result = hello(text: "hello world!")
    print(result)
    

    🍎 字符串

    🌲 定义字符串

    var my_str = "123"
    

    🌲 获取字符串

    // 从头截取两个字符
    my_str[my_str.index(my_str.startIndex, offsetBy: 0) ... my_str.index(my_str.startIndex, offsetBy: 1)] // 12
    // 从头截取两个字符
    my_str[...my_str.index(my_str.startIndex, offsetBy: 1)] // 12
    // 截取完整字符串
    my_str[stmy_strr.index(my_str.startIndex, offsetBy: 0)...my_str.index(my_str.endIndex, offsetBy: -1)] // 123
    // 或
    my_str[my_str.index(my_str.startIndex, offsetBy: 0)...]
    // 或
    my_str[...]
    

    🌲 拼接字符串

    // 加号拼接
    my_str2 = my_str + "456" // 123456
    // 数组拼接
    my_str2 = ["123", "456", "789"].joined() // 123456789
    // format
    var my_str2 = "\(my_str)456" // 123456
    

    🌲 替换字符串

    // 将第一个字符替换成12
    my_str.replaceSubrange(my_str.index(my_str.startIndex, offsetBy: 0)...my_str.index(my_str.startIndex, offsetBy: 0), with: "12") // 1223
    

    🌲 查找字符串位置

    print(my_str.range(of: "2"))
    // Optional(Range(Swift.String.Index(_rawBits: 65536)..<Swift.String.Index(_rawBits: 131072)))
    

    🌲 遍历字符串

    for s in my_str {
        print(s)
    }
    

    🍎 数组

    🌲 定义数组

    var my_arr = [1, 2, 3]
    

    🌲 获取元素

    // 通过下标获取 下标从0开始
    print(my_arr[0]) // [1, 2, 3]
    

    🌲 添加元素

    my_arr.append(4) 
    print(my_arr) // [1, 2, 3, 4]
    

    🌲 删除元素

    // 移除第三个元素
    my_arr.remove(at: 3)
    print(my_arr) // [1, 2, 3]
    

    🌲 截取元素

    // 截取第一个元素
    my_arr[0...0] // [1]
    或
    my_arr[0..<1] // [1]
    // 某一个位置截取到最后
    my_arr[0...] // [1, 2, 3]
    my_arr[1...] // [2, 3]
    // 从开始截取到某一个位置
    my_arr[...0] // [1]
    my_arr[...(my_arr.count - 1)] // [1, 2, 3]
    // 截取所有元素
    my_arr[...]
    

    🌲 拼接数组

    my_arr.append(contentsOf: [4, 5, 6]) // [1, 2, 3, 4, 5, 6]
    

    🍎 字典

    🌲 定义字典

    var my_dic = ["name": "张三", "age": "18"]
    

    🌲 获取元素

    var name = my_dic["name"]
    print(name ?? "") // 张三
    

    🌲 添加元素

    my_dic["gender"] = "男"
    print(my_dic) // ["gender": "男", "age": "18", "name": "张三"]
    

    🌲 删除元素

    my_dic.removeValue(forKey: "name")
    print(my_dic) // ["age": "18"]
    

    🌲 截取字典

    无法截取
    

    🌲 拼接字典

    无法拼接
    

    🍎 元组

    🌲 定义元组

    var my_tuple = (0, "66", 2)
    var my_tuple2 = (name: "张三", age: 18)
    

    🌲 获取元素

    # 通过下标获取 下标从0开始
    print(my_tuple.0) // 0
    print(my_tuple2.name) // 张三
    

    🌲 添加元素

    元组不能修改, 所以无法添加
    

    🌲 删除元素

    元组不能修改, 所以无法删除
    

    🌲 截取元素

    无法截取
    

    🌲 拼接元组

    无法拼接
    

    🍎 集合

    🌲 定义集合

    var my_set: Set = [1, 2, 3, 1] // [3, 2, 1] 无序
    var my_set2 = Set([1, 2, 3, 2]) // [2, 1, 3] 无序
    

    🌲 获取元素

    # 集合不能获取元素 但可以先转成数组再操作
    var my_arr = my_set.sorted()
    print(my_arr[0])
    

    🌲 添加元素

    my_set.insert(4)
    print(my_set) // [3, 1, 4, 2] 无序
    

    🌲 删除元素

    my_set.remove(1)
    print(my_set) // [3, 4, 2] 无序
    

    🌲 截取元素

    无法截取 - 可以转化成数组后截取
    

    🌲 拼接集合

    var my_set: Set = [1, 2, 3]
    var my_set2 = Set([1, 2, 3, 4])
    // 交集
    print(my_set.intersection(my_set2)) // [1, 2, 3] 无序
    // 并集
    my_set.formUnion(my_set2)
    print(my_set) // [1, 2, 3, 4] 无序
    // 补集 前者补给后者的值 - - 颠倒过来后返回是 [] 因为没有可补的
    print(my_set2.subtracting(my_set)) // [4]
    

    🍎 条件语句

    🌲 if

    let a = 1
    // 如果a等于1 执行条件
    if a == 1 {
        print("a等于1")
    }
    

    🌲 if - else if

    let a = 2
    // 如果a等于1执行1 如果a等于2执行2
    if a == 1 {
        print("a等于1")
    } else if a == 2 {
        print("a等于2")
    }
    

    🌲 if - else if - else

    let a = 3
    # 如果都不等 执行else
    if a == 1 {
        print("a等于1")
    } else if a == 2 {
        print("a等于2")
    } else {
        print("a既不等于1也不等于2")
    }
    

    🍎 循环语句

    🌲 for

    for i in [1, 2, 3] {
        print(i) // 1 2 3
    } 
        
    for i in 0...3 {
        print(i) // 0 1 2 3
    }
    
    [1, 2, 3].forEach({item in
        print(item)
    }) // 1 2 3
    

    🌲 while

    var i = 0
    while i < 3 {
        print(i) // 0 1 2
        i += 1
    }
    

    🍎 Block

    🌲 无参数无返回值

    let testBlock = { () -> Void in
        print("无参数无返回值")
    }
    // 或
    let testBlock = { () in
        print("无参数无返回值")
    }
    // 或
    let testBlock = {
        print("无参数无返回值")
    }
    
    // 执行
    testBlock()
    
    // 直接执行: 末位加括号 下文略
    {
        print("无参数无返回值")
    }()
    

    🌲 有参数无返回值(单参数, 多参数)

    let testBlock = { (a: String) -> Void in
        print(a)
    }
    // 或
    let testBlock = { a in
        print(a)
    }
    
    // 执行
    testBlock("有参数无返回值") // 有参数无返回值
    
    // 多参数 两个或两个以上必须加括号 而且第二个参数类型不可推导 只能定义类型
    let testBlock = { (a, b: String) in
        print(a)
    }
    testBlock(123, "123") // 123
    

    🌲 有参数有返回值

    let testBlock = { (a: String) -> String in
        return a
    }
    // 或
    let testBlock = { a -> String in
        return a
    }
    print(testBlock("有参数有返回值"))
    

    🌲 回调

    func hello(a: String, block: @escaping () -> Void) {
        DispatchQueue.global().asyncAfter(deadline: .now() + 2, execute: {
            block()
        })
    }
    
    // 执行
    hello(a: "123", block: {
        print("回调结束")
    })
    // 或
    hello(a: "123") {
        print("回调结束")
    }
    
    print("执行完毕")
    
    /**
    执行完毕
    回调结束
    */
    
    
    // 两个Block参数
    func hello(a: String, block: @escaping () -> Void, block2: @escaping () -> Void) {
        DispatchQueue.global().asyncAfter(deadline: .now() + 2, execute: {
            block()
            block2()
        })
    }
    
    // 执行 使用方法的时候 Xcode会自动提示这种写法
    hello(a: "123") {
    
    } block2: {
    
    }
    
    // Block参数后面还有参数
    func hello(a: String, block: @escaping () -> Void, block2: @escaping () -> Void, b: String) {
        DispatchQueue.global().asyncAfter(deadline: .now() + 2, execute: {
            block()
            block2()
        })
    }
    
    // 执行 同样Xcode会自动提示这种写法
    hello(a: "123", block: {
    
    }, block2: {
    
    }, b: "145456")
    

    🌲 排序

    // 从小到大
    let numbers = [1, 2, 5, 4, 3, 6, 8, 7]
    let sortNumbers = numbers.sorted(by: { a, b in a < b })
    print("numbers - " + "\(sortNumbers)") // [1, 2, 3, 4, 5, 6, 7, 8]
    // 或
    let numbers = [1, 2, 5, 4, 3, 6, 8, 7]
    let sortNumbers = numbers.sorted(by: { return $0 < $1 })
    print("numbers - " + "\(sortNumbers)") // [1, 2, 3, 4, 5, 6, 7, 8]
    // 或
    let numbers = [1, 2, 5, 4, 3, 6, 8, 7]
    let sortNumbers = numbers.sorted(by: { $0 < $1 })
    print("numbers - " + "\(sortNumbers)") // [1, 2, 3, 4, 5, 6, 7, 8]
    // 或
    let numbers = [1, 2, 5, 4, 3, 6, 8, 7]
    let sortNumbers = numbers.sorted(by: < )
    print("numbers - " + "\(sortNumbers)") // [1, 2, 3, 4, 5, 6, 7, 8]
    
    //从大到小 - 修改符号即可
    let numbers = [1, 2, 5, 4, 3, 6, 8, 7]
    let sortNumbers = numbers.sorted(by: > )
    print("numbers - " + "\(sortNumbers)") // // [1, 2, 3, 4, 5, 6, 7, 8]
    

    🌲 筛选

    let numbers = [1, 2, 5, 4, 3, 6, 8, 7]
    let filterNumbers = numbers.filter({ $0 % 2 == 0 })
    print(filterNumbers)
    

    🍎 类和对象

    🌲 类

    class Persion {
    
    }
    

    🌲 定义成员变量

    class Persion {
        var name: String? // 可选类型
        var age: Int = 0 // 普通变量
    }
    

    🌲 定义初始化方法

    class Persion {
      var name: String?
      var age: Int = 0
      // 初始化方法
      init(name: String, age: Int) {
          self.name = name
          self.age = age
      }
    }
            
    # 初始化
    
    # 方法1
    var per = Persion(name: "张三", age: 16)
    # 方法2
    var per2 = Persion.init(name: "李四", age: 18)
    

    🌲 定义方法

    class Persion {
        var name: String?
        var age: Int = 0
    
        init(name: String, age: Int) {
            self.name = name
            self.age = age
        }
    
        func say() {
            print("人说")
        }
      
        static func say() {
            print("人类说")
        }
    }
    
    # 调用
    var per = Persion(name: "张三", age: 16)
    per.say() // 人说
    
    Persion.say() // 人类说
    

    🌲 继承

    class Student: Persion {
        override func say() {
            print("学生说")
        }
    }
    
    let stu = Student(name: "学生0", age: 18)
    stu.say() // 学生说
    

    🍎 类型转换

    🌲 String & Int (Double/Float通用)

    // String -> Int
    let a = "123"
    let b = Int(a)
    print(b ?? "")
    
    // Int -> String
    let a = 123
    let b = String(a)
    print(b)
    
    // Double 
    let a = "123"
    let b = Double(a)
    print(b ?? "")
    
    // Float
    let a = "123"
    let b = Float(a)
    print(b ?? "")
    

    🍎 反射

    var mirror: Mirror? = Mirror(reflecting: stu);
    repeat {
        mirror?.children.forEach({child in
            print(child.label ?? "")
            print(type(of: child.value))
        })
        mirror = mirror?.superclassMirror ?? nil
    } while (mirror != nil)
    
    /**
    id
    Optional<String>
    name
    Optional<String>
    age
    Int
    */
    

    🍎 GCD

    🌲 主队列 / 全局队列

    // 主队列
    DispatchQueue.main
    // 全局队列
    DispatchQueue.global()
    
    执行任务是用抛的方式 把xx任务抛到某个队列中 队列会分配合适的线程去执行任务
    - 抛到主队列中的任务由主线程执行
    - 抛到全局队列中的任务 可能由主线程执行 也可能由子线程执行
    

    🌲 线程阻塞

    即主线程中执行`耗时任务`或`等待`
    
    `耗时任务`: 例如从1循环到1亿
    `等待`: 例如 sleep(5)
    

    🌲 串行并行

    串行: 按顺序执行
    并行: 同时执行
    
    常见的串行队列
    DispatchQueue.main 
    常见的并行队列
    DispatchQueue.global()
    

    🌲 主队列执行任务(同步)

    DispatchQueue.main.sync {
        print("主线程中同步执行任务")
        print(Thread.current)
    }
    
    print("执行完毕")
    
    /**
    崩溃
    该方法不能在主线程中执行 因为会阻塞
    Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
    */
    

    🌲 主队列执行任务(异步)

    DispatchQueue.main.async {
        print("主线程中异步执行任务")
        print(Thread.current)
    }
    
    print("执行完毕")
    
    /**
    执行完毕
    主线程中异步执行任务
    <NSThread: 0x60000174c380>{number = 1, name = main}
    */
    

    🌲 全局队列执行任务(同步)

    可以看到虽然把任务抛到了global队列 但任务还是在主线程执行的

    DispatchQueue.global().sync {
        print("主线程中同步执行任务")
        print(Thread.current)
    }
    
    print("执行完毕")
    
    /**
    子线程中同步执行任务
    <NSThread: 0x60000039c240>{number = 1, name = main}
    执行完毕
    */
    

    🌲 全局队列执行任务(异步)

    DispatchQueue.global().async {
        print("子线程中异步执行任务")
        print(Thread.current)
    }
    
    print("执行完毕")
    
    /**
    执行完毕
    子线程中异步执行任务
    <NSThread: 0x600000e57240>{number = 3, name = (null)}
    */
    

    🌲 全局队列回到同步主队列

    DispatchQueue.global().sync {
        // 全局队列的同步在主线程执行
        print("主线程中同步执行任务")
        print(Thread.current)
        DispatchQueue.main.sync {
            print("主线程中同步执行任务")
            print(Thread.current)
        }
        print("子线程执行完毕")
        print(Thread.current)
    }
    
    print("执行完毕")
    
    /**
    主线程中同步执行任务
    <NSThread: 0x6000000b86c0>{number = 1, name = main}
    (lldb)  
    崩溃: 
    */
    

    🌲 全局队列回到异步主队列

    DispatchQueue.global().async {
        print("子线程中异步执行任务")
        print(Thread.current)
        DispatchQueue.main.sync {
            print("主线程中同步执行任务")
            print(Thread.current)
        }
        print("子线程执行完毕")
        print(Thread.current)
    }
    
    print("执行完毕")
    
    /**
    执行完毕
    子线程中异步执行任务
    <NSThread: 0x6000016a2000>{number = 4, name = (null)}
    主线程中同步执行任务
    <NSThread: 0x60000169c200>{number = 1, name = main}
    子线程执行完毕
    <NSThread: 0x6000016a2000>{number = 4, name = (null)}
    */
    
    DispatchQueue.global().async {
        print("子线程中异步执行任务")
        print(Thread.current)
        DispatchQueue.main.async {
            print("主线程中异步执行任务")
            print(Thread.current)
        }
        print("子线程执行完毕")
        print(Thread.current)
    }
    
    print("执行完毕")
    
    /**
    执行完毕
    子线程中异步执行任务
    <NSThread: 0x60000332a200>{number = 9, name = (null)}
    子线程执行完毕
    <NSThread: 0x60000332a200>{number = 9, name = (null)}
    主线程中异步执行任务
    <NSThread: 0x60000336c240>{number = 1, name = main}
    */
    

    🌲 连续全局队列任务(异步)

    for i in 1...5 {
        DispatchQueue.global().async {
            print("子线程异步任务\(i)")
        }
    }
    
    print("执行完毕")
    
    > 顺序不固定
    
    /**
    执行完毕
    子线程异步任务2
    子线程异步任务3
    子线程异步任务4
    子线程异步任务5
    子线程异步任务1
    /**
    

    🌲 连续全局队列任务(同步)

    for i in 1...5 {
        DispatchQueue.global().sync {
            // 全局队列的同步在主线程执行
            print("主线程同步任务\(i)")
        }
    }
    
    print("执行完毕")
    
    > 顺序固定
    
    // 主线程同步任务1
    // 主线程同步任务2
    // 主线程同步任务3
    // 主线程同步任务4
    // 主线程同步任务5
    // 执行完毕
    

    🌲 自定义队列

    let queue = DispatchQueue(label: "my_queue", qos: .default, attributes: .concurrent, autoreleaseFrequency: .inherit, target: nil)
    
    queue.async {
    
    }
    
    attributes
    - .concurrent 并行
    - .initiallyInactive 崩溃
    - DispatchQueue.Attributes() 串行
    
    DispatchQoS
    - .userInteractive 需要用户交互的, 优先级最高, 和主线程一样
    - .userInitiated 即将需要, 用户期望优先级, 优先级高比较高
    - .default 默认优先级
    - .utility 需要执行一段时间后, 再通知用户, 优先级低
    - *.background 后台执行的, 优先级比较低
    - *.unspecified 不指定优先级, 最低
    
    autoreleaseFrequency
    - .inherit 表示不确定, 之前默认的行为也是现在的默认值
    - .workItem 表示为每个执行的项目创建和排除自动释放池, 项目完成时清理临时对象
    - .never 表示GCD不为您管理自动释放池
    
    target
    - 传入nil默认子线程
    - 传入 DispatchQueue.main 则为主线程
    

    🌲 串行队列

    // 快速创建串行队列
    let queue = DispatchQueue(label: "my_serial_queue");
    
    for i in 0...100 {
        queue.async {
            print("\(i)");
        }
    }
    
    // 0
    // 1
    // ...
    // 100
    

    🌲 延时(After)

    DispatchQueue.main.asyncAfter(deadline: .now() + 3, execute: {
        print(Thread.current)
        print("延迟3s")
    })
    
    /**
    <NSThread: 0x600000ef83c0>{number = 1, name = main}
    延迟3s
    */
    
    DispatchQueue.global().asyncAfter(deadline: .now() + 3, execute: {
        print(Thread.current)
        print("延迟3s")
    })
    
    /**
    <NSThread: 0x600000eb04c0>{number = 5, name = (null)}
    延迟3s
    */
    

    🌲 并行同步group_notiify(分组通知)

    并行同步: 任务同时执行 每个任务中执行的程序是同步按顺序执行的

    let group = DispatchGroup()
    let queue = DispatchQueue.main
    
    queue.async(group: group, execute: {
        print(Thread.current)
        print("任务1")
    })
    
    queue.async(group: group, execute: {
        print(Thread.current)
        print("任务2")
    })
    
    group.notify(queue: queue, execute: {
        print(Thread.current)
        print("任务执行完毕")
    })
    
    /**
    <NSThread: 0x600002304740>{number = 1, name = main}
    任务1
    <NSThread: 0x600002304740>{number = 1, name = main}
    任务2
    <NSThread: 0x600002304740>{number = 1, name = main}
    任务执行完毕
    */
    
    let group = DispatchGroup()
    let queue = DispatchQueue.global()
    
    queue.async(group: group, execute: {
        print(Thread.current)
        print("任务1")
    })
    
    queue.async(group: group, execute: {
        print(Thread.current)
        print("任务2")
    })
    
    group.notify(queue: queue, execute: {
        print(Thread.current)
        print("任务执行完毕")
    })
    
    /**
    <NSThread: 0x600003318cc0>{number = 8, name = (null)}
    <NSThread: 0x600003330780>{number = 9, name = (null)}
    任务1
    任务2
    <NSThread: 0x600003330780>{number = 9, name = (null)}
    任务执行完毕
    */
    

    🌲 并行异步group_notiify(分组通知)

    并行异步: 任务同时执行 每个任务中执行的程序有可能是异步的 比如网络请求 说不定什么时间执行完

    let group = DispatchGroup()
    let queue = DispatchQueue.global()
    
    group.enter()
    queue.async {
        print("简单任务1")
        group.leave()
    }
    
    group.enter()
    queue.async {
        queue.asyncAfter(deadline: .now() + 3, execute: {
            print("耗时任务2")
            group.leave()
        })
    }
    
    group.notify(queue: DispatchQueue.main, execute: {
        print("完成")
    })
    

    并行同步的分组通知可以监测并行同步程序的同时结束 但是对于并行异步程序就不能准确收到执行结束的通知 如果要判断异步的结束 需要使用 enter() 和 leave() 当所有enter被leave之后 程序才会调用notify

    🌲 信号量

    信号量wait会阻塞线程 直到收到signal才放开阻塞 利用这一点可以来顺序执行代码 group.enter 底层就是信号量

    let sem = DispatchSemaphore(value: 1)
    
    sem.wait()
    DispatchQueue.global().asyncAfter(deadline: .now() + 1, execute: {
        print("任务1")
        sem.signal()
    })
    
    sem.wait()
    DispatchQueue.global().asyncAfter(deadline: .now() + 1, execute: {
        print("任务2")
        sem.signal()
    })
    
    sem.wait()
    DispatchQueue.global().asyncAfter(deadline: .now() + 1, execute: {
        print("任务3")
        sem.signal()
    })
    
    print("执行完毕")
    
    value: 每次执行几个任务 如果为2 会自动执行 2个wait 后面的代码
    
    /**
    任务1
    任务2
    执行完毕
    任务3
    
    注: 你可能会有一个疑问 为什么`执行完毕`会先于`任务3`执行 因为async是异步 同步要比异步执行的快 sem.wait执行后系统会阻塞线程并开始执行后面的代码直到收到sem.signal才放开阻塞
    */
    
    但是上面的写法是在主线程中使用信号量 如果执行耗时任务会造成阻塞 导致界面卡顿 所以一般情况下不这么使用
    所以还是在子线程中使用比较好 不会阻塞
    
    // 异步
    let sem = DispatchSemaphore(value: 1)
    
    DispatchQueue.global().async {
        sem.wait()
        DispatchQueue.global().asyncAfter(deadline: .now() + 1, execute: {
            print("任务1")
            sem.signal()
        })
    
        sem.wait()
        DispatchQueue.global().asyncAfter(deadline: .now() + 3, execute: {
            print("任务2")
            sem.signal()
        })
    
        sem.wait()
        DispatchQueue.global().asyncAfter(deadline: .now() + 1, execute: {
            print("任务3")
            sem.signal()
        })
    
        sem.wait()
        DispatchQueue.global().asyncAfter(deadline: .now() + 1, execute: {
            print("任务4")
            sem.signal()
        })
    
        print("执行完毕")
    }
    

    🌲 信号量 - 让程序不结束

    let semaphore = DispatchSemaphore(value: 0).wait(timeout: .now() + 100)
    

    🍎 异常处理

    🌲 try

    // 常规try 异常中断并执行catch
    do {
        let data = try Data(contentsOf: URL(string: "https://www.baidu.com")!)
        let str = String(data: data, encoding: .utf8)
        debugPrint(str ?? "")
    } catch let err {
        debugPrint(err)
    }
    // 不打印
    do {
        let data = try Data(contentsOf: URL(string: "https://www.baidu.com")!)
        let str = String(data: data, encoding: .utf8)
        print(str ?? "")
    } catch {
        
    }
    // 不捕获 - 报错直接崩溃
    let data = try Data(contentsOf: URL(string: "https://www.baidu.com")!)
    let str = String(data: data, encoding: .utf8)
    print(str ?? "")
    

    🌲 try?

    // 问try 异常即return
    guard let data = try? Data(contentsOf: URL.init(string: "htt123ps://www.baidu.com")!) else {
        return
    }
    let str = String(data: data, encoding: .utf8)
    debugPrint(str ?? "")
    

    🌲 try!

    // `强try` 异常即崩溃
    let data = try! Data(contentsOf: URL.init(string: "https://www.baidu.com")!)
    let str = String(data: data, encoding: .utf8)
    debugPrint(str ?? "")
    

    相关文章

      网友评论

          本文标题:[iOS] Swift学习文档 - 白猫版

          本文链接:https://www.haomeiwen.com/subject/lgoncrtx.html