第二章学习笔记-swift语法

Apr 22, 2024

100小时后请叫我苹果开发者

运算符、条件判断及类型

运算符

  • 代码注释 ///* */

  • 常量:let 变量:var

  • 数学运算符: + - * / % += -= *= /=

  • 逻辑运算符: Bool && || !

  • 比较运算符: >= > <= < ==

条件判断

  • 条件运算符: if else、 else if 、 ?: 、 switch 、default

if else:

if condition {
} else if condition1 {
} else {
}

区间: 1…7 2..<9

switch:

switch{
case 1:
}

类型 Types

  • 常见类型: Int 、Double、Bool、String
  • 类型转换: String(50)
  • 字符串插值: "\(day)"

用函数将代码归类为功能

  • 第一版写法:增加参数
func driveTowards(direction: Srting, meters: Int){}

driveTowards(directions: "", meters: 100)
  • 第二版写法: 增加参数标签

若希望省略参数标签,可使用 swift 语言的省略符号 _

func driveTowards(_ direction: String, for meters: Int){}

driveTowards("", for: 100)
  • 第三版写法:增加默认值
func driveTowards(_ direction: String = "", for meters: Int){}

driveTowaords(for: 100)
  • 返回值:
func rollDice() -> Int {
  Int.random(in: 1...6)
}

用集合与循环处理数据

集合类型数组 Array

var weightRecordsA = [70.4, 70.3, 70.1]

var weightRecordsB: [Double] = []

常见方法

  • 添加: append , insert(_:, at:)
  • 删除:remove, removeAll, removeSubrange
  • 使用: randomElement , firstIndex(of: )
  • 修改: sort , shuffle , map , filter
  • 判断: count , min , isEmpty , contains

var arr = [70.4, 70.3, 70.1]

// 添加

arr.append(80.2)

arr += [89.1, 33.3]

arr.insert(70.2, at: 3)

// 删除

arr.remove(at: 2)

arr.removeSubrange(3...7)

arr.removeAll()

// 使用

arr[1]

arr.randomElement()

arr.firstIndex(of: 70.2)

// 原位修改

arr[0] = 89.2

arr.sort()

arr.shuffle()

// 新数组修改

newArr = arr.map { ($0 - targetWeight) }

newArr = arr.filter { $0 - 79.2 }

// 判断数组当前状态

arr.count

arr.isEmpty

arr.min()

arr.contains(77.2)

集合类型字典 Dictionary

let PhoneBookA: [String: Int] = [:]

let PhoneBookB= ["老王":12345]
  • 增: phoneBookB["new"] = 2134213
  • 删: phoneBookB[:"new"] = nil
  • 查: phoneBookB["老王"]
  • 改: phoneBookB["老王"] = 544332
  • 状态: .count .isEmpty .contains(where: { $0.key == "老王" })

循环

  • for in , while condition {} , repeat {} while condition

编程范型,闭包及可选类型

闭包

  • 闭包与函数的区别:省略函数名、增加了 in 语法、前移花括号
// 函数
func isTheFirstSmallerThanSecond(first: Int, second: Int) -> Bool {
  return first < second
}

// 闭包

let closure = { (first: Int, second: Int) -> Bool in
  return first < second
}

// by: 使用

numberArr.sort(by: closure)
  • 用法 1 不构建常量:适用于单次使用函数
numberArr.sort(by: { (first: Int, second: Int) -> Bool in
  return first < second
})
  • 用法 2 尾部闭包:对有闭包作为参数的函数,若其最后一个参数 Argument 为闭包,则可省略参数标签及括号。
numberArr.sort { (first: Int, second: Int) -> Bool in
  return fisrt < second
}
  • 用法 3 省略类型:定义时已明确的闭包的类型,可省略
numbersArr.sort { (first, second) in
  return first < second

进一步省略参数位置的括号、函数功能代码仅存在一行返回值时,关键词 return 可省略

numbers.sort { first, second in first < second }
  • 短参数写法:在使用短参数时,参数名和关键词 in 都可以省略
numberArr.sort { $0 < $1 }

可选类型 Optional

// num可以存储 数字/空 两个状态
let num: Int? = 1
  • 强行读取 ! :绝对确定变量中有包裹值的情况下,才可以使用强行读取值的感叹号。
var username: String? = "小王"

print(username!)
  • 判断后读取
if username != b {
  let safelyUnwrappedUsername = username!
  print("\(safelyUnwrappedUsername),想听点什么")
}
  • if let 语法:自动判断包裹值是否为空,若不为空则赋给新的常量适用,并执行花括号里面的代码。新的常量仅在当前花括号内存在。
if let safelyUnwrappedUsername = username {
  print("\(safelyUnwrappedUsername),想听点什么")
}
  • guard let 语法:该语法创建的常量可在父级别内的花括号内使用

func guardDemo() {
  guard let safelyUnwrappedUsername = username else{
    print("username = nil")
    return
  }
   print("\(safelyUnwrappedUsername),想听点什么")
}
  • 为可选类型增加默认值 ??
var username = nil;

print("\(username ?? "你好"), 想听点什么?")

用「结构」创建自定义类型

  • 基本的 struct
struct Player {
  static var allPlayers: [Player] = []

  var name: String

  var livesRemaining = 5 {
    willSet {
      print("警告 还剩下\(newValue) 条命")
    }
    didSet {
      if livesRemaining != 0 {
        print("已满血复活")
      } else {
        print("游戏结束")
      }
    }
  }

  let maxHealth = 100
  lazy var currentHealth = maxHealth

  var isPlayerOutOfLives: Bool {
    get {
      livesRemaining == 0 ? true : false
    }
    set {
      if newValue {
        livesRemaining = 0
      }
    }
  }

  init(name: String) {
    self.name = name ;
  }

  init(name: String, livesRemaining: Int, currentHealth: Int){
    self.name = name
    self.livesRemaining = livesRemaining
    self.currentHealth = currentHealth
  }

  mutating func damaged(by health: Int){}

  static func recentAddedPlayer() -> Player {
    allPlayers[allPlayers.count - 1]
  }

}

let player = Player(name: "player")

player.name
  • 可变更 mutating:若方法函数需要更改属性的数值,则需要在方法的关键词 func 前加上另一个关键词 mutating
  • lazy:告知编译器先忽略 lazy 关键词后的赋值语句,直接完成对该结构体剩余代码的编码。当该变量真正被需要时,再完成赋值。
let maxHealth = 100
lazy var currentHealth = maxHealth
  • 属性观察器 willSetdidSet
var a = 4 {
  willSet {
    newValue
  }
  didSet {
    oldValue
  }
}
  • 预计算属性 getset
var b: Bool {
  get {
    // 设定b的值
  }
  set {
    // 修改其他属性的值
    newValue
  }
}
  • init 自定义初始化器
  • 类型属性,关键词为 static。调用类型属性的语法为 结构名称.类型属性 ,与其相似的还有类型方法。
struct Player{
  static var allPlayers: [Player] = []
  static func recentAddedPlayer() -> Player {
    allPlayers[allPlayers.count - 1]
  }
}

var wang = Player(name:"wang")

Player.allPlayers.append(contentsOf: [wang])
Player.recentAddedPlayer().name

将信息归类

  • 枚举: enum ...case
enum Source{
  case num1
  case num2
}

var a =Source.num1

switch a{
  case .num1:
}
  • 可选类型:Optional.none ,等于 nil

  • 类class

与struc 区别:class 与struct 在内存中的存储方式不同;class 支持创建更复杂的父子关系,而struct 不支持;class 必须写明初始化器,而struct 自带默认的初始化器。

覆盖 override ;继承父类 super;

class 子类实体在同一个数组中转化为父类,以满足数组仅能存储同一类型数值的要求。判断数组中是否存在子类型的关键词是is。判断并改变类型的语法是as? (符合特征,则创类型变量)

for car in cars {
  if car is Truck {}

  if let teslaModel3 = car as? Sedan{}
}
  • extension 扩展现有类型的内容,支持预计算属性、初始化器及方法,支持struct、class、enum、protocool。
extension Car {
  var quckInfo: String {
    "The car brand is \(brand)"
  }
}

用协议建立规则

别名 typealias

  • 类型分类:根据其存储性质划分为值类型 Value Type 如 struct、int,或引用类型 Reference Type 如 class;根据其是否由 swift 语言提供来划分分为基础类型 Basic Type 如 Int、Double、String,或自定义类型 Custom Type 如 enum、class、struct
  • 别名允许你给现有的类型起另外一个名称。
typealias PhoneBook = [String: Int]
typealias Age = Int

用协议建立规则

协议 Protocol 表明做法,但不具体提供做什么,类似后端的Service 和 ServiceImpl 里的 Service,支持struct、class、enum

// 描述性的protocol
protocol Expressible {
  var name: String { get }
  init(name: String)
}
// 以下两种使用写法效果一致
struct User: Expressible{
  var name: String
}

extension User: Expressible {}

属性Property:需统一使用关键词 var ,只读可改都需标明 { get set }

常见的协议类型

Equatable(可等性)、Comparable(可比性)、Hashable(可哈希性)、Identifiable(可辨识性)、Codable(可编码性)

  • Equatable:

在自定义类中可比较,因为 == 不支持比较自定义类型。
若自定义类型中仅包含基础类型,则可以省略类方法 static func == (Self, Self) -> Bool 的写法

struct Todo: Equatable {
  var content: String;
  // ignore
  static func ==(lhs:Todo,rhs:Todo)->Bool{
    return lhs.content == rhs.content
  }
}
  • Comaprable:
extesnion Todo: Comparable {
  static func < (lhs: Todo, rhs: Todo) -> Bool {}

}
  • Hashable:

Hash 是将现有的数据结构通过一定预算转化为一个随机的、不可重复的、独特的值,

struct day: Hashable{}
let todoOne = day()
let todoTwo = day()
// 对于字典的key来说,其数值应该是唯一的。
let todos = [dayOne:todoOne,dayTwo:todoTwo]
  • Identifiable:

可辨识性协议要求我们添加一个名为 id 的属性,该属性必须包含一个可哈希的数值,名为 id。

strcut Todo: Equatable, Identifiable {
  var content: String;
  var id = UUID()
}

异常处理及 App 的生命周期

  • fatalError() 模拟一个严重错误,让程序运行到这行代码时彻底停止。

  • Error 代表异常协议

  • do-try-catch 实践:

enum PasswordError: Error {
  case notLongEnough
}

func validatePassword(_ password: String) throws -> Bool {
  if password.count < 6{
    throw PasswordError.notLongEnough
  }
  return true;
}

var password = "1234"

do{
   try validatePassword(password)
   print("pass")
} catch passwordError.notLongEnough {
  print("at least 6")
}
  • try? 不具备添加额外代码的地方,主要用于获取该函数的返回值; try! 确信不会报错,报错直接中断程序运行
if let validated = try? validatePassword(password) {
  print("passed")
} else {
  print("at least 6")
}

// try! 运行函数,但彻底忽略错误
try! validatePassword(password)

生命周期

  • Unattached(未读取) :应用完全没有被运行,也不存在于内存中的情况。
  • Foreground Inactive(前台不活跃) :短暂的过渡状态,应用已经在屏幕上,但还不会对用户操作作出反馈。
  • Foreground Active(前台活跃):运行
  • Background(后台):应用存在于内存中,可以继续运行代码,并且随时准备再次使用。
  • Suspended(挂起):在后台长期没有被使用,则会进入挂起状态,在此状态中,则处于挂起状态的应用随时会被系统从内存中移除来让出空间。

Task Async Await

var body: some View{
  Text("Concurrency")
    .task {
      await truck()
  }
}

func truck() async {
  // 一些繁琐任务
  for i in 0...<1_000_000_000{
    print(i)
  }
}

>

cd ..
CC BY-NC-SA 4.0 2024-PRESENT © Kelsey Shi