1
  • 指令式编程 imperative,C、C++,写给计算机的语言
  • 声明式编程 declarative,用DSL或函数式编程实现,函数式编程用 reduce、map、sorted 等,写给人看的语言
  • DSL Domain-Specific Language 领域特定语言,代表SQL
  • Combine 响应式编程框架 ,处理数据流
  • FRP Functional reactive programming 函数响应式编程
  • 枚举遵从 CaseIterable 协议,有allCases 属性,返回所有枚举类型组成的数组
  • 元组取下标,用的是点语法,temp.1
  • reduce(0, +) ,数组取第一个 .first
  • 声明式UI起源Elm语言,后继者 React的Component、Flutter的Widget
  • Redux、Flux 思想来源 Elm,状态管理和组件通信架构,Store、State、Action。在大中型项目中应用可以,小项目应用由于其引入的复杂度会得不偿失。
  • SwiftUI 和 UIKit 可以兼容使用
2
  • 刷新预览的快捷键是 Option + Command + P
  • Text 有属性 font,foregroundColor,padding、background,.minimumScaleFactor(0.5)缩放系数 .lineLimit(1) 限制一行,传入nil不限制。foregroundColor 可以设置.primary 能自适应亮暗模式。
  • 字体还有 .headline,.body 等,按数值指定 .font(.system(size: 48))、自定义字体 .font(.custom(“Copperplate”, size: 48))。使用预定义字体可适配动态类型特性。
  • Color(_:red:green:blue:) 提供色彩空间和 RGB 值来设置颜色。可以颜色名字从 Assets.xcassets 中加载颜色,Color(“colorName”)
  • 使用 Assets.xcassets 颜色的好处,可以根据设备类型设置不同颜色,为亮暗设置不同颜色,可以用16进制定义
  • .padding(.top, 16) .padding(.horizontal, 8) 等同 [.leading, .trailing] 都是8。.padding(.trailing, 24)
  • 封装类的 modifier 的顺序重要,例如 padding,background
  • .frame(width: 88, height: 88) 指定尺寸,frame(minWidth: 0, maxWidth: .infinity, alignment: .trailing) 指定最小最大宽,对其方式
  • .clipShape(Circle()) 正方形内画圆,.clipShape(Capsule()) 胶囊形状
  • Button.init(action:label:) label 接受一个闭包,是一个 ViewBuilder。或一个 title 一个 action
  • 可以使用 CGFloat CGSize,可以遵从 View 协议自定义 View
  • ForEach 列举元素,数组中元素需遵从 Identifiable 协议,或通过 ForEach(row, id: .self) 让元素支持 Hashable 也可以。
  • VStack、HStack,VStack(spacing: 8) 指定间距,VStack(alignment: .trailing) 指定对齐方式
  • if case 匹配的用法
  • Spacer() 可伸缩空白
  • .scaleEffect(scale) 做缩放
3 数据状态和绑定
  • 限定小数格式,例如8位以内。
1
2
3
4
5
6
7
8
9
var formatter: NumberFormatter = {
let f = NumberFormatter()
f.minimumFractionDigits = 0
f.maximumFractionDigits = 8
f.numberStyle = .decimal
return f
}()
//将Double类型的 value 转为字符串
formatter.string(from: value as NSNumber)!
  • Double(result) 将字符串转为浮点数,可失败构造器
  • 字符串String 有 contains(“.”) 方法,是否包含某字符串,返回Bool类型。遵从序列化协议 Sequence 的类型,有starts(with: “-“),是否以某个内容开头。字符串、数组都可以用
1
2
3
let b = [1,2,3,4]
b.starts(with: [1,2])
//返回true,传入空数组[] 也会返回 true
  • 可选值类型,可使用map,例如下例转浮点数为字符串,返回值也是可选类型
1
2
let result: Double? = 3.14
result.map { String($0) }
  • 纯函数:返回值只依赖入参,不改变其外部作用域的变量状态的函数
  • @State 修饰,内部会被转换为一对 setter 和 getter,其赋值操作会引起界面刷新。
  • @Binding 修饰,将值语义的属性 “转换” 为引用语义,传递属性时,使用$符号,称为投影属性(projection property)
  • @State 和 @Binding 都是属性包装(Property Wrapper),属性包装可以简化代码。一段示例(77页)
  • @State 适合 struct 或者 enum 这样的值类型,局限在body中使用,需要再view外部操作数据就不行。如果需要多个view共享和更改数据模型,使用ObservableObject。
  • 遵从ObservableObject 协议,调用 objectWillChange.send() 或使用 @Published 修饰 都可以在属性发生改变时,去更新UI
  • 数组 .joined() 合并为字符串。数组取片段的用法,下例。
1
2
history = Array(total[..<index])
temporaryKept = Array(total[index...])
  • reduce 用法,一种。
1
2
3
brain = history.reduce(CalculatorBrain.left("0"), { result, item in
result.apply(item: item)
})
  • Slider 滑块用法,接受一个绑定值 Binding
1
Slider(value: $model.slidingIndex, in: 0...Float(model.totalCount), step: 1)
  • 按钮 modal 行为展示视图
1
2
3
4
5
Button("操作履历:\(model.history.count)") {
self.editingHistory = true
}.sheet(isPresented: self.$editingHistory, content: {
HistoryView(model: self.model)
})
  • @EnvironmentObject 可以在view层级上避免不必要的属性传递,在初始化父视图的地方初始化数据,在深层子层级上可以直接使用。