SwiftUI学习笔记day5:Lecture 5 Stanford CS193p 2023

在这里插入图片描述

  • 课程链接:Lecture 5 Stanford CS193p 2023
  • 代码仓库:iOS
  • 课程大纲:
  1. Enum

    • 定义:enum MyType { … }
    • 关联值:case drink(name: String, oz: Int)
    • 匹配:switch … case let .drink(n, o): …
    • 扩展:CaseIterable、原始值、indirect
  2. Optional

    • 本质:enum Optional<Wrapped> { case none; case some(Wrapped) }
    • 解包:if letguard letswitch
    • 便捷:? 链式调用、?? 合并、map/flatMap
  3. 闭包 & 函数参数

    • 语法:(Int)->String,尾随闭包 { … }
    • 标记:@escaping(存储/异步)、@autoclosure(延迟求值)
    • 捕获:[weak self] 防止循环引用
  4. 计算属性 & Subscript

    • 计算属性:var area: Double { get …; set … }
    • 下标:subscript(i, j) -> T { get/set }
    • 延迟存储:lazy var x = …
  5. Extension

    • 增加:方法、计算属性、构造器、下标、嵌套类型
    • 限制:不能加存储属性
    • 范型/协议扩展:extension Array where Element: Equatable { … }

核心:理解 Swift 核心类型背后都是枚举和函数,借助模式匹配、闭包、属性特性和扩展写出简洁、安全的代码。


Lecture 5 Stanford CS193p 2023

文章目录

  • SwiftUI学习笔记day5:Lecture 5 Stanford CS193p 2023
  • Lecture 5 Stanford CS193p 2023
  • 1.enum
    • 1.1 基础定义
    • 1.2 关联值(Associated Data)
    • 1.3 类型推断与简写
    • 1.4 状态检查(`switch`)
    • 1.5 `break` 与 `fallthrough`
    • 1.6 注意事项
    • 1.7 拓展用法
    • 1.8 `default` 分支
    • 1.9 关联值的取出(`let` 语法)
    • 1.10 遍历所有 case:`CaseIterable`
  • 2. Optional(可选类型)
    • 2.1 定义
    • 2.2 样例
    • 2.3 注意事项
    • 2.4 拓展
  • 2. Functions as Arguments(函数/闭包作为参数)
    • 2.1定义
    • 2.2样例(MemoryGame)
    • 2.3注意事项
    • 2.4拓展
  • 3. 计算属性(`get` / `set`)
    • 3.1定义
    • 3.2样例(MemoryGame 的唯一翻面卡索引)
    • 3.3注意事项
    • 3.4拓展
  • 4. Extension(扩展)
    • 4.1 定义
    • 4.2 注意事项
    • 4.3 拓展

1.enum


1.1 基础定义

enum FastFoodMenuItem {case hamburgercase friescase drinkcase cookie
}
  • 值类型:枚举实例传递或赋值时会被拷贝。
  • 协议支持:可实现 EquatableHashableCaseIterableCustomStringConvertible 等。

1.2 关联值(Associated Data)

enum FastFoodMenuItem {case hamburger(numberOfPatties: Int)case fries(size: FryOrderSize)case drink(String, ounces: Int)    // 第一个参数未命名case cookie
}enum FryOrderSize { case large, small }
  • 定义:每个 case 自带不同类型/数量的数据。

  • 构造示例

    let order1 = FastFoodMenuItem.hamburger(numberOfPatties: 2)
    let order2 = FastFoodMenuItem.drink("Coke", ounces: 12)
    
  • 匹配与解包

    switch order2 {
    case .drink(let brand, let oz):print("\(brand)\(oz)oz")
    default:break
    }
    

1.3 类型推断与简写

let item1 = FastFoodMenuItem.hamburger(numberOfPatties: 2)
var item2: FastFoodMenuItem = .cookie   // 可省略枚举名
// var item3 = .cookie                  // 无上下文时编译失败
  • 要求:只有当变量/参数处显式声明了枚举类型,才能在赋值处写成 .caseName

  • 函数调用推断

    func serve(_ item: FastFoodMenuItem) {}
    serve(.fries(size: .large))
    

1.4 状态检查(switch

switch menuItem {
case .hamburger:print("burger")
case .fries:print("fries")
case .drink:print("drink")
case .cookie:print("cookie")
}
  • 强制穷举:必须覆盖所有 case 或提供 default

  • 忽略关联值case .drink: 等同于 case .drink(_, _)

  • 条件匹配

    switch order {
    case .hamburger(let n) where n > 2:print("大份汉堡")
    default:break
    }
    

1.5 breakfallthrough

  • break
    Swift switch 不会自动穿透,空 case 可省略 break

  • fallthrough

    switch code {
    case 401:print("Unauthorized")fallthrough
    case 403:print("Forbidden")
    default:break
    }
    

    fallthrough 仅跳到下一个 case,不会重新判断条件或解包关联值。


1.6 注意事项

  • 关联值比较:自动合成的 Hashable/Equatable 会将关联值纳入比较。

  • ID 冲突:使用 CaseIterable 时要避免不同枚举重复。

  • 递归枚举:使用 indirect 支持递归结构。

    indirect enum Expr {case number(Int)case add(Expr, Expr)
    }
    
  • 同名枚举:在多枚举同名 case 场景下,赋值处需显式指明类型以消除歧义。


1.7 拓展用法

  1. CaseIterable

    enum FastFoodMenuItem: CaseIterable {case hamburger, fries, drink, cookie
    }
    FastFoodMenuItem.allCases  // [.hamburger, .fries, ...]
    
  2. 原始值枚举

    enum HTTPStatus: Int {case ok = 200, notFound = 404, unauthorized = 401
    }
    HTTPStatus(rawValue: 404)  // .notFound
    
  3. 协议实现

    • 自定义 CustomDebugStringConvertible 打印关联值细节。
    • 实现 Codable 可直接 JSON 序列化/反序列化。
  4. 模式匹配

    if case .cookie = item {print("吃饼干")
    }
    

1.8 default 分支

  • 用途:当你只关注部分 case,其它“其余情况”可统一归入 default

  • 示例

    var menuItem = FastFoodMenuItem.cookieswitch menuItem {
    case .hamburger:print("🍔")
    case .fries:print("🍟")
    default:print("其它")      // cookie、drink 都走到这里
    }
    // 输出:"其它"
    
  • 注意

    • 一旦包含了 default,编译器将不再强制你穷举所有具体 case。
    • 若同时存在 default 且又写了所有 case,则 default 只处理未来新增或遗漏的 case。

1.9 关联值的取出(let 语法)

  • 目的:在 switch 中解包并绑定每个 case 的关联数据。

  • 核心写法

    switch order {
    case .hamburger(let patties):print("汉堡:\(patties) 份")
    case .fries(let size):print("薯条:\(size)")
    case .drink(let brand, let ounces):print("\(brand)\(ounces)oz")
    case .cookie:print("饼干")
    }
    
  • 同类写法

    case let .hamburger(patties):// 与上面等价
    
  • 注意

    • 可省略标签位置,但位置与类型必须一一对应。
    • 若只想匹配而不需要值,可写成 case .drink:(等同于 .drink(_, _))。

1.10 遍历所有 case:CaseIterable

  • 定义:让枚举自动生成一个静态数组 allCases,包含所有 case。

  • 示例

    enum TeslaModel: CaseIterable {case X, S, three, Y
    }// 遍历
    for model in TeslaModel.allCases {print(model)
    }
    // 输出:X S three Y
    
  • 应用

    • 快速构建 UI 列表:

      Picker("选择车型", selection: $selectedModel) {ForEach(TeslaModel.allCases, id: \.self) { m inText("\(m)")}
      }
      
    • 批量统计/上报:

      func reportSales() {TeslaModel.allCases.forEach { model inreportSales(for: model)}
      }
      
  • 注意

    • 仅支持无关联值的简单枚举。
    • 若有关联值/原始值枚举,需自行实现 allCases

2. Optional(可选类型)

2.1 定义

在 Swift 中,Optional 就是一个带有关联值的枚举:

enum Optional<Wrapped> {case nonecase some(Wrapped)
}
  • none:表示“缺值”(nil)。
  • some(Wrapped):表示“有值”,其中 Wrapped 是任意类型。

2.2 样例

let possibleName: String? = "Alice"
let noName: String?     = nil// 强制解包(可能崩溃)
print(possibleName!)     // "Alice"
// print(noName!)        // Crashes// 安全解包—if let
if let name = possibleName {print("Hello, \(name)")
} else {print("No name")
}// 安全解包—guard let
func greet(_ name: String?) {guard let n = name else {print("Missing name"); return}print("Hi, \(n)")
}// switch+pattern
switch possibleName {
case .none:print("无值")
case .some(let actual):print("值是:\(actual)")
}

2.3 注意事项

  1. 强制解包风险
    使用 ! 前须确保非 nil,否则运行时崩溃。

  2. Optional chaining

    let length = possibleName?.count  // 返回 Int? 
    
  3. Nil 合并运算符

    let displayName = possibleName ?? "Guest"//等价于如下:let displayName = possibleName != nil ? possibleName! : "Guest"
    
  4. map / flatMap

    let upper = possibleName.map { $0.uppercased() }        // String?
    let num   = Int("123").flatMap { $0 * 2 }               // Int?
    

2.4 拓展

  • guard vs if:建议在函数开头用 guard 提前退出,保持主逻辑左括号少嵌套。

  • 自定义解包:自定义操作符或扩展,比如

    postfix operator ??
    postfix func ??<T>(value: T?) -> T {return value ?? fatalError("Unexpected nil")
    }
    
  • Optional 本质:知道它就是个枚举,能帮助你用 switch、关联值等枚举技巧处理它。


2. Functions as Arguments(函数/闭包作为参数)

2.1定义

Swift 函数是第一类类型,可以作为参数、返回值或存储:

func foo(x: Int) -> String {}func bar(transform: (Int) -> String) {let s = transform(42)print(s)
}
bar(transform: foo)           // 传函数名
bar { "\($0)" }               // 传尾随闭包

2.2样例(MemoryGame)

struct MemoryGame<CardContent> {var cards: [Card]// cardContentFactory: 从索引 Int 构造内容的闭包init(numberOfPairs: Int, cardContentFactory: (Int) -> CardContent) {cards = []for pairIndex in 0..<numberOfPairs {let content = cardContentFactory(pairIndex)cards.append(Card(content: content, id: pairIndex*2))cards.append(Card(content: content, id: pairIndex*2+1))}}
}
// 调用方式:
let game = MemoryGame<String>(numberOfPairs: 5,cardContentFactory: { index inreturn ["🐶","🐱","🐭","🦊","🐻"][index]}
)
// 或者尾随闭包
let game2 = MemoryGame<Int>(numberOfPairs: 3) { $0 * $0 }

2.3注意事项

  1. @escaping

    • 如果闭包被保存在实例中、或异步调用,参数需标记 @escaping
    init(factory: @escaping (Int)->CardContent) {}
    
  2. @autoclosure

    • 用于延迟求值、消除调用时 {}
    func log(_ message: @autoclosure ()->String) {}
    log("Hello \(Date())")  // 自动转换为闭包
    
  3. 捕获列表

    • 小心闭包对外部变量/self 的捕获,可能导致循环引用。
    class A {lazy var printer: ()->Void = { [weak self] in print(self?.description) }
    }
    

2.4拓展

  • 高阶函数mapfilterreduce 都是典型示例。
  • 函数组合:可用自定义运算符将多个 (A)->B 链接成一个。
  • 协议与闭包:有时可用协议替代闭包,取决于代码可读性和扩展性需求。

3. 计算属性(get / set

3.1定义

computed property:不存储值,而是通过 getset 动态计算。

struct Circle {var radius: Double// 只读var area: Double {return .pi * radius * radius}// 读写var diameter: Double {get { return radius * 2 }set { radius = newValue / 2 }}
}

3.2样例(MemoryGame 的唯一翻面卡索引)

struct MemoryGame<CardContent> {private(set) var cards: [Card]// 只读或读写private var indexOfTheOneAndOnlyFaceUpCard: Int? {get {let faceUpIndices = cards.indices.filter { cards[$0].isFaceUp }return faceUpIndices.count == 1 ? faceUpIndices.first : nil}set {// 将所有卡片翻到 newValue,或都背面for idx in cards.indices {cards[idx].isFaceUp = (idx == newValue)}}}mutating func choose(_ card: Card) {if let chosenIndex = cards.firstIndex(matching: card),let potentialMatch = indexOfTheOneAndOnlyFaceUpCard {// ... 匹配逻辑indexOfTheOneAndOnlyFaceUpCard = nil} else {indexOfTheOneAndOnlyFaceUpCard = cards.firstIndex(matching: card)}}
}

3.3注意事项

  1. newValue

    • set 中默认参数名是 newValue,也可自定义:

      set(updatedIndex) {}
      
  2. 只能用于计算属性

    • willSet/didSet 只能用于存储属性,不能与 get/set 同时使用。
  3. 性能

    • 复杂计算应避免在频繁访问的属性里卡顿,可考虑缓存或存储属性。

3.4拓展

  • lazy var

    • 延迟初始化存储属性,第一次访问时计算并保存。
  • 下标(subscript

    • 类似计算属性,可带 get/set

      struct Matrix {var data: [Double]let rows, cols: Intsubscript(r: Int, c: Int) -> Double {get { data[r*cols + c] }set { data[r*cols + c] = newValue }}
      }
      

4. Extension(扩展)

4.1 定义

使用 extension,可为已有类型(structclassenumprotocol)新增功能:

extension String {// 计算属性var isPalindrome: Bool {let s = lowercased().filter { $0.isLetter }return s == String(s.reversed())}// 方法func truncated(to length: Int) -> String {return (count > length) ? prefix(length) + "…" : self}// 下标subscript(idx: Int) -> Character {self[index(startIndex, offsetBy: idx)]}// 嵌套类型enum Kind { case vowel, consonant, other }
}

4.2 注意事项

  1. 不能添加存储属性

    • 只能新增计算属性、方法、构造器(init)、下标、嵌套类型、协议遵循。
  2. 协议扩展

    • 可给协议提供“默认实现”:

      protocol Drawable { func draw() }
      extension Drawable {func draw() { print("Default draw") }
      }
      
  3. 命名冲突

    • 与原类型或其他扩展同名成员,后加载的会覆盖,需谨慎避免冲突。

4.3 拓展

  • 条件扩展

    • 为满足特定 where 条件的泛型类型扩展:

      extension Array where Element: Equatable {func occurrences(of x: Element) -> Int {filter { $0 == x }.count}
      }
      
  • 模块统一

    • 将常用工具方法放在单独文件,通过 extension 统一管理。
  • 链式调用

    • 为类型添加可变方法,并返回 Self 支持链式:

      extension UIView {@discardableResultfunc corner(radius: CGFloat) -> Self {layer.cornerRadius = radius; return self}
      }
      view.corner(radius: 8).backgroundColor = .red
      

总结

  • Optional:理解其枚举本质,安全解包与链式操作。
  • 函数参数:灵活运用闭包、尾随、@escaping@autoclosure
  • 计算属性get/set 强大,能实现高度封装。
  • Extension:无侵入地增强类型功能,写出更优雅、可复用的代码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/86702.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/86702.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/86702.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

idea 报错:java: 非法字符: ‘\ufeff‘

idea 报错&#xff1a;java: 非法字符: ‘\ufeff‘ 解决方案&#xff1a;

数据结构与算法之美:图

Hello大家好&#xff01;很高兴我们又见面啦&#xff01;给生活添点passion&#xff0c;开始今天的编程之路&#xff01; 我的博客&#xff1a;<但凡. 我的专栏&#xff1a;《编程之路》、《数据结构与算法之美》、《题海拾贝》、《C修炼之路》 欢迎点赞&#xff0c;关注&am…

SpringBoot -- 热部署

9.SpringBoot 热部署&#xff08;自动重启&#xff09; 在实际开发过程中&#xff0c;每次修改代码就得将项目重启&#xff0c;重新部署&#xff0c;对于一些大型应用来说&#xff0c;重启时间需要花费大量的时间成本。对于一个后端开发者来说&#xff0c;重启过程确实很难受啊…

HarmonyOS 5浏览器引擎对WebGL 2.0的支持如何?

以下是HarmonyOS 5浏览器引擎对‌WebGL 2.0‌支持的详细技术分析&#xff1a; 一、核心支持能力 ‌系统能力声明 HarmonyOS 5 浏览器引擎通过 SystemCapability.Graphic.Graphic2D.WebGL2 提供对 WebGL 2.0 的底层支持 支持的关键特性包括&#xff1a; OpenGL ES 3.0 特性…

Class1线性回归

Class1线性回归 买房预测 要根据历史数据来预测一套房子的价格。你发现影响房价的因素有很多&#xff0c;于是你决定使用线性回归模型来预测房价。 影响房价的因素如下&#xff1a; 房屋面积&#xff08;平方米&#xff09; 房龄&#xff08;年&#xff09; 离地铁站的距离&a…

Vue.js 3:重新定义前端开发的进化之路

Vue.js 3&#xff1a;重新定义前端开发的进化之路 引言&#xff1a;一场酝酿已久的革新 2020年9月18日&#xff0c;Vue.js团队以代号"One Piece"正式发布3.0版本&#xff0c;这不仅是框架发展史上的重要里程碑&#xff0c;更是前端工程化领域的一次革命性突破。历经…

Unity性能优化-渲染模块(1)-CPU侧(1)-优化方向

Unity 中渲染方面的优化大致可以划分为以下几块核心内容&#xff1a; CPU 优化 (减少 Draw Calls 和 CPU 瓶颈) GPU 优化 (减少像素着色和 GPU 瓶颈) 内存和显存优化 (Resource Management) 光照优化 (Lighting & Global Illumination) 这四个方面是相互关联的。一个方…

AI矢量图与视频无痕修复:用Illustrator与After Effects解锁创作新维度

最近因一个项目&#xff0c;有机会深度体验了奥地利Blueskyy艺术学院授权的Adobe教育版全家桶&#xff0c;过程中发现了不少令人惊喜的“黑科技”&#xff0c;很想和大家分享这份发掘宝藏的喜悦。一句话总结这次体验&#xff1a;慷慨且稳定。比如&#xff0c;它每周提供高达150…

Maven Javadoc 插件使用详解

Maven Javadoc 插件使用详解 maven-javadoc-plugin 是 Maven 项目中用于生成 Java API 文档的标准插件&#xff0c;它封装了 JDK 的 javadoc 工具&#xff0c;提供了更便捷的配置和集成方式。 一、基本使用 1. 快速生成 Javadoc 在项目根目录执行以下命令&#xff1a; bas…

Apache Kafka 面试应答指南

Apache Kafka 核心知识详解与面试应答指南 一、Apache Kafka 概述 Apache Kafka 作为一款分布式流处理框架,在实时构建流处理应用领域发挥着关键作用。其最广为人知的核心功能,便是作为企业级消息引擎被众多企业采用。 二、消费者组 (一)定义与原理 消费者组是 Kafka 独…

在NVIDIA Jetson和RTX上运行Google DeepMind的Gemma 3N:多模态AI的边缘计算革命

在NVIDIA Jetson和RTX上运行Google DeepMind的Gemma 3N&#xff1a;多模态AI的边缘计算革命 文章目录 在NVIDIA Jetson和RTX上运行Google DeepMind的Gemma 3N&#xff1a;多模态AI的边缘计算革命引言&#xff1a;多模态AI进入边缘计算时代文章结构概览 第一章&#xff1a;Gemma…

iOS打包流程中的安全处理实践:集成IPA混淆保护的自动化方案

随着iOS应用上线节奏的加快&#xff0c;如何在持续集成&#xff08;CI&#xff09;或交付流程中嵌入安全处理手段&#xff0c;成为开发团队构建自动化发布链路时不可忽视的一环。特别是在App已经完成构建打包&#xff0c;准备分发前这一阶段&#xff0c;对IPA进行结构层面的加固…

FFmpeg进行简单的视频编辑与代码写法实例

使用 FFmpeg 进行简单的视频编辑非常强大。它是一个命令行工具&#xff0c;虽然一开始可能看起来有点复杂&#xff0c;但掌握了基本命令后会非常有用。 以下是一些常见的简单视频编辑操作及其 FFmpeg 命令&#xff1a; 1. 剪切视频 如果你想从一个视频中剪切出一段&#xff0…

如何使用免费软件写论文?六个免费论文生成软件使用指南

在学术写作中&#xff0c;利用AI技术和免费的写作工具可以极大地提高效率&#xff0c;尤其对于需要处理大量文献、结构化写作的论文来说&#xff0c;使用合适的软件能节省时间&#xff0c;提升论文质量。这里为您推荐六个免费的论文生成软件&#xff0c;并提供使用指南&#xf…

大数据系统架构实践(二):Hadoop集群部署

大数据系统架构实践&#xff08;二&#xff09;&#xff1a;Hadoop集群部署 文章目录 大数据系统架构实践&#xff08;二&#xff09;&#xff1a;Hadoop集群部署一、Hadoop简介二、部署前准备三、部署Hadoop集群1. 下载并解压安装包2. 配置hadoop-env.sh3. 配置core-site.xml4…

42道Maven高频题整理(附答案背诵版)

1.简述什么是Maven&#xff1f; Maven是一个项目管理和构建自动化工具&#xff0c;主要服务于Java项目。使用Maven&#xff0c;开发者可以方便地管理项目的构建、文档生成、报告、依赖、SCM&#xff08;软件配置管理&#xff09;、发布和分发等过程。 Maven的核心概念是基于项…

【数字后端】- 如何进行时钟树综合?

首先&#xff0c;要明确的是&#xff0c;时钟树综合只有命令去操作这一种方式 CTS的步骤 1、时钟树综合前的准备工作-设置时钟树cell&#xff08;每个项目必做&#xff09; 最简单的项目要设置生长时钟树时可用的clock buffer和clock inverter cell list&#xff0c;如下 此…

OpenCV CUDA模块设备层-----像素值进行逐通道的最大值比较函数max()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 是 OpenCV 的 CUDA 模块&#xff08;cv::cudev&#xff09; 中的一个 设备端内联函数&#xff08;device function&#xff09;&#xff0c;用于…

SCSAI万物对象模型和五维市场交易平台原型

一个完整的工业软件对象模型平台&#xff0c;基于SCSAI对象模型和五维市场理论。该平台包含对象管理、五维市场交易和大模型集成功能。 工业软件对象模型平台功能说明 这个平台实现了基于Aras Innovator对象模型和五维市场理论的工业软件解决方案&#xff0c;主要功能包括&…

昇腾のPrefix Cache

Prefix Cache特性介绍 Prefix Cache 即前缀缓存&#xff0c;是一种用于优化大语言模型&#xff08;LLM&#xff09;推理性能的技术&#xff0c;主要应用于多轮对话、系统提示等具有大量共同前缀的场景。 原理 LLM 推理计算主要包括 Prefill 阶段&#xff08;Prompt 计算&…