- 筆記
筆記
本篇文章記錄一下100 Days of SwiftUI
第15天的筆記內(nèi)容辫呻,因?yàn)榈?5天是對(duì)Swift 簡(jiǎn)介的總結(jié),所以包含了前14天的筆記內(nèi)容,具備Swift基礎(chǔ)的同學(xué)可以跳過這部分筆記
創(chuàng)建常量和變量
// Swift可以創(chuàng)建常量和變量泄私,但是常量通常更合適
// 變量
var name = "Ted"
name = "Rebecca"
// 常量
let user = "Daphne"
// 打印
print(user)
字符串
let actor = "Tom Cruise"
let actor = "Tom Cruise ??♂?"
// 特殊符號(hào)轉(zhuǎn)轉(zhuǎn)義前面加 \
let quote = "He tapped a sign saying \"Believe\" and walked away."
// 跨越多行的字符串
let movie = """
A day in
the life of an
Apple engineer
"""
// 獲取字符數(shù)量.count
print(actor.count)
// 字符串是否以特定字母開頭或結(jié)尾
print(quote.hasPrefix("He"))
print(quote.hasSuffix("Away.")) // Swift 中的字符串區(qū)分大小寫,因此這里返回 false
整數(shù)
// Int
let score = 10
let higherScore = score + 10
let halvedScore = score / 2
// 支持復(fù)合賦值運(yùn)算符
var counter = 10
counter += 5
// 是否能被某個(gè)數(shù)整除
let number = 120
print(number.isMultiple(of: 3))
// 特定范圍內(nèi)生成隨機(jī)數(shù)
let id = Int.random(in: 1...1000)
浮點(diǎn)數(shù)
// Double
let score = 3.0
布爾類型
let goodDogs = true
let gameOver = false
// 反轉(zhuǎn)值
var isSaved = false
isSaved.toggle()
拼接字符串
let name = "Taylor"
let age = 26
let message = "I'm \(name) and I'm \(age) years old."
print(message)
數(shù)組
var colors = ["Red", "Green", "Blue"]
let numbers = [4, 8, 15, 16]
var readings = [0.1, 0.5, 0.8]
print(colors[0])
print(readings[2])
// 添加元素
colors.append("Tartan")
// 刪除指定元素
colors.remove(at: 0)
print(colors.count)
// 是否包含某個(gè)元素
print(colors.contains("Octarine"))
字典
let employee = [
"name": "Taylor",
"job": "Singer"
]
// 訪問的元素不存在則會(huì)使用default的值
print(employee["name", default: "Unknown"])
print(employee["job", default: "Unknown"])
集合
// 集合與數(shù)組類似执庐,但是是無序的受楼,且忽略重復(fù)值
var numbers = Set([1, 1, 3, 5, 7])
print(numbers)
// 添加元素
numbers.insert(10)
枚舉
enum Weekday {
case monday, tuesday, wednesday, thursday, friday
}
var day = Weekday.monday
day = .friday
類型注釋
let player: String = "Roy"
var luckyNumber: Int = 13
let pi: Double = 3.141
var isEnabled: Bool = true
var albums: Array<String> = ["Red", "Fearless"]
var user: Dictionary<String, String> = ["id": "@twostraws"]
var books: Set<String> = Set(["The Bluest Eye", "Foundation"])
// 數(shù)組和字典常用寫法
var albums: [String] = ["Red", "Fearless"]
var user: [String: String] = ["id": "@twostraws"]
// 創(chuàng)建空的字符串?dāng)?shù)據(jù)
var teams: [String] = [String]()
var clues = [String]()
// 枚舉
enum UIStyle {
case light, dark, system
}
var style: UIStyle = .light
if判斷語句
let age = 16
if age < 12 {
print("You can't vote")
} else if age < 18 {
print("You can vote soon.")
} else {
print("You can vote now.")
}
// && 組合條件是兩個(gè)部分都為真時(shí),整個(gè)條件才為真皮钠,|| 則是其中任意一個(gè)條件為真,整個(gè)條件就為真
let temp = 26
if temp > 20 && temp < 30 {
print("It's a nice day.")
}
Switch開關(guān)語句
enum Weather {
case sun, rain, wind
}
let forecast = Weather.sun
switch forecast {
case .sun:
print("A nice day.")
case .rain:
print("Pack an umbrella.")
default:
print("Should be okay.")
}
三元運(yùn)算符
let age = 18
let canVote = age >= 18 ? "Yes" : "No"
循環(huán)
for循環(huán)
let platforms = ["iOS", "macOS", "tvOS", "watchOS"]
for os in platforms {
print("Swift works on \(os).")
}
// 1...12是1到12赠法,包含12
for i in 1...12 {
print("5 x \(i) is \(5 * i)")
}
// 1..<13是1到12麦轰,不包含13
for i in 1..<13 {
print("5 x \(i) is \(5 * i)")
}
// 不需要循環(huán)變量可以使用_
var lyric = "Haters gonna"
for _ in 1...5 {
lyric += " hate"
}
print(lyric)
while循環(huán)
var count = 10
while count > 0 {
print("\(count)…")
count -= 1
}
print("Go!")
// continue跳過當(dāng)前的循環(huán)迭代并繼續(xù)執(zhí)行以下循環(huán)
// break退出循環(huán)并跳過所有剩余迭代
let files = ["me.jpg", "work.txt", "sophie.jpg"]
for file in files {
if file.hasSuffix(".jpg") == false {
continue
}
print("Found picture: \(file)")
}
函數(shù)
for i in 1...12 {
print("\(i) x \(number) is \(i * number)")
}
}
printTimesTables(number: 5)
// 返回值
func rollDice() -> Int {
return Int.random(in: 1...6)
}
let result = rollDice()
print(result)
// 如果函數(shù)僅包含一行代碼可以省略return
func rollDice() -> Int {
Int.random(in: 1...6)
}
函數(shù)返回多個(gè)值
func getUser() -> (firstName: String, lastName: String) {
(firstName: "Taylor", lastName: "Swift")
}
let user = getUser()
print("Name: \(user.firstName) \(user.lastName)")
// 如果不需要元祖中的所有值,可以解構(gòu)元組砖织,jiang將其分解為單獨(dú)的值款侵,_可以會(huì)兒一些值
let (firstName, _) = getUser()
print("Name: \(firstName)")
自定義參數(shù)標(biāo)簽
// 如果調(diào)用函數(shù)時(shí)不想傳遞參數(shù)名可以在參數(shù)名前面加_
func isUppercase(_ string: String) -> Bool {
string == string.uppercased()
}
let string = "HELLO, WORLD"
let result = isUppercase(string)
// 設(shè)置函數(shù)外部、內(nèi)部參數(shù)侧纯,for為外部參數(shù)新锈,number為內(nèi)部參數(shù)
func printTimesTables(for number: Int) {
for i in 1...12 {
print("\(i) x \(number) is \(i * number)")
}
}
printTimesTables(for: 5)
提供參數(shù)的默認(rèn)值
func greet(_ person: String, formal: Bool = false) {
if formal {
print("Welcome, \(person)!")
} else {
print("Hi, \(person)!")
}
}
greet("Tim", formal: true)
greet("Taylor")
處理函數(shù)中的錯(cuò)誤
// 定義可能發(fā)生的錯(cuò)誤
enum PasswordError: Error {
case short, obvious
}
// 編寫可以拋出錯(cuò)誤的函數(shù)
func checkPassword(_ password: String) throws -> String {
if password.count < 5 {
throw PasswordError.short
}
if password == "12345" {
throw PasswordError.obvious
}
if password.count < 10 {
return "OK"
} else {
return "Good"
}
}
let string = "12345"
// 通過do包含拋出異常函數(shù),用try調(diào)用拋出異常函數(shù)眶熬,然后捕獲發(fā)生的錯(cuò)誤
// 捕獲錯(cuò)誤時(shí)妹笆,需要有一個(gè)catch可以處理各種錯(cuò)誤
do {
let result = try checkPassword(string)
print("Rating: \(result)")
} catch PasswordError.obvious {
print("I have the same combination on my luggage!")
} catch {
print("There was an error.")
}
閉包
// 可以將功能直接分配給常量或變量
let sayHello = {
print("Hi there!")
}
sayHello()
// 接受參數(shù)块请,用in來標(biāo)記參數(shù)和返回類型的結(jié)束,in后面是閉包本身的主體
let sayHello = { (name: String) -> String in
"Hi \(name)!"
}
let team = ["Gloria", "Suzanne", "Tiffany", "Tasha"]
let onlyT = team.filter({ (name: String) -> Bool in
return name.hasPrefix("T")
})
// 閉包在Swift中的使用拳缠,例如filter()方法通過測(cè)試運(yùn)行數(shù)組的所有元素墩新,測(cè)試為true的元素都會(huì)在新數(shù)組中返回
let team = ["Gloria", "Suzanne", "Tiffany", "Tasha"]
let onlyT = team.filter({ (name: String) -> Bool in
return name.hasPrefix("T")
})
print(onlyT) // ["Tiffany", "Tasha"]
// 對(duì)上述閉包進(jìn)行改造,因?yàn)殚]包主體只有一行代碼窟坐,可以刪除return
let onlyT = team.filter({ (name: String) -> Bool in
name.hasPrefix("T")
})
// 忽略閉包中的指定類型
let onlyT = team.filter({ name in
name.hasPrefix("T")
})
// 改造為尾隨閉包的特殊語法
let onlyT = team.filter { name in
name.hasPrefix("T")
}
// Swift提供簡(jiǎn)短的參數(shù)名稱海渊,可以使用的$0
let onlyT = team.filter {
$0.hasPrefix("T")
}
結(jié)構(gòu)體
// 結(jié)構(gòu)體可以創(chuàng)建自定義數(shù)據(jù)類型,并且具有自己的屬性和方法
struct Album {
let title: String
let artist: String
var isReleased = true
func printSummary() {
print("\(title) by \(artist)")
}
}
// 使用初始化器創(chuàng)建結(jié)構(gòu)體實(shí)例
let red = Album(title: "Red", artist: "Taylor Swift")
print(red.title)
red.printSummary()
// 結(jié)構(gòu)體方法更改其屬性時(shí)需要標(biāo)記為mutating
mutating func removeFromSale() {
isReleased = false
}
計(jì)算屬性
struct Employee {
let name: String
var vacationAllocated = 14
var vacationTaken = 0
// 計(jì)算屬性在每次訪問時(shí)都會(huì)計(jì)算其值
var vacationRemaining: Int {
vacationAllocated - vacationTaken
}
}
// 計(jì)算屬性提供了getter和setter方法
var vacationRemaining: Int {
get {
vacationAllocated - vacationTaken
}
set {
vacationAllocated = vacationTaken + newValue
}
}
屬性觀察器
// 屬性觀察器是在屬性更改時(shí)運(yùn)行的代碼片段
// didSet在屬性剛剛更改時(shí)運(yùn)行狸涌,willSet在屬性更改之前運(yùn)行
struct Game {
var score = 0 {
didSet {
print("Score is now \(score)")
}
}
}
var game = Game()
game.score += 10
game.score -= 3
自定義初始化器
struct Player {
let name: String
let number: Int
init(name: String) {
self.name = name
number = Int.random(in: 1...99)
}
}
訪問控制
// Swift 有多種用于結(jié)構(gòu)內(nèi)部訪問控制的選項(xiàng)切省,但最常見的是四種:
// private:不要讓結(jié)構(gòu)體之外的任何東西使用它
// private(set):結(jié)構(gòu)之外的任何內(nèi)容都可以讀取此內(nèi)容,但不要讓他們更改它
// fileprivate:不要讓當(dāng)前文件之外的任何內(nèi)容使用它
// public:讓任何人帕胆、任何地方都可以使用它
struct BankAccount {
private(set) var funds = 0
mutating func deposit(amount: Int) {
funds += amount
}
mutating func withdraw(amount: Int) -> Bool {
if funds > amount {
funds -= amount
return true
} else {
return false
}
}
}
let account = BankAccount(funds: 100)
print(account. funds) // ?
account.funds += 100 // ?
靜態(tài)屬性和方法
struct AppData {
static let version = "1.3 beta 2"
static let settings = "settings.json"
}
print(AppData.version)
類
// 類與結(jié)構(gòu)體的區(qū)別一:可以通過繼承其他類創(chuàng)建類
class Employee {
let hours: Int
init(hours: Int) {
self.hours = hours
}
func printSummary() {
print("I work \(hours) hours a day.")
}
}
class Developer: Employee {
func work() {
print("I'm coding for \(hours) hours.")
}
}
let novall = Developer(hours: 8)
novall.work()
novall.printSummary()
// 如果子類想更改從父類獲得的方法朝捆,必須使用override
override func printSummary() {
print("I spend \(hours) hours a day searching Stack Overflow.")
}
// 類與結(jié)構(gòu)體的區(qū)別二:初始化器不同
// 1.Swift 不會(huì)為類生成成員初始化器。(類的初始化比結(jié)構(gòu)體復(fù)雜得多)
// 2.如果子類具有自定義初始值設(shè)定項(xiàng)懒豹,則它必須始終在完成設(shè)置自己的屬性后調(diào)用父類的初始值設(shè)定項(xiàng)芙盘。
// 3.如果子類沒有任何初始值設(shè)定項(xiàng),它將自動(dòng)繼承其父類的初始值設(shè)定項(xiàng)脸秽。
class Vehicle {
let isElectric: Bool
init(isElectric: Bool) {
self.isElectric = isElectric
}
}
class Car: Vehicle {
let isConvertible: Bool
init(isElectric: Bool, isConvertible: Bool) {
self.isConvertible = isConvertible
// 即上述的第二點(diǎn)
super.init(isElectric: isElectric)
}
}
// 類與結(jié)構(gòu)體的區(qū)別三:類實(shí)例的所有副本共享其數(shù)據(jù)(類型引用)儒老,而結(jié)構(gòu)體不是(值引用)
class Singer {
var name = "Adele"
}
var singer1 = Singer()
var singer2 = singer1
singer2.name = "Justin"
print(singer1.name) // Justin,如果是Struct則是Adele
print(singer2.name) // Justin记餐,如果是Struct則是Justin
// 類與結(jié)構(gòu)體的區(qū)別四:類可以有一個(gè)析構(gòu)器驮樊,當(dāng)對(duì)對(duì)象的最后一個(gè)引用被銷毀時(shí),該析構(gòu)器被調(diào)用
class User {
let id: Int
init(id: Int) {
self.id = id
print("User \(id): I'm alive!")
}
deinit {
print("User \(id): I'm dead!")
}
}
for i in 1...3 {
let user = User(id: i)
print("User \(user.id): I'm in control!")
}
// 類與結(jié)構(gòu)體的區(qū)別五:即使類本身是常量片酝,類也允許我們更改變量屬性囚衔,類不需要mutating使用關(guān)鍵字來更改其數(shù)據(jù)
class User {
var name = "Paul"
}
let user = User()
user.name = "Taylor"
print(user.name)
協(xié)議
// 協(xié)議定義了我們期望數(shù)據(jù)類型支持的功能,而 Swift 確保我們的代碼遵循這些規(guī)則
protocol Vehicle {
func estimateTime(for distance: Int) -> Int
func travel(distance: Int)
}
struct Car: Vehicle {
func estimateTime(for distance: Int) -> Int {
distance / 50
}
func travel(distance: Int) {
print("I'm driving \(distance)km.")
}
}
// 可以編寫一個(gè)接受任何符合Vehicle類型的函數(shù)
func commute(distance: Int, using vehicle: Vehicle) {
if vehicle.estimateTime(for: distance) > 100 {
print("Too slow!")
} else {
vehicle.travel(distance: distance)
}
}
let car = Car()
commute(distance: 100, using: car)
// 協(xié)議可以添加屬性
protocol Vehicle {
var name: String { get } // 標(biāo)記為get雕沿,可能是常量或計(jì)算屬性
var currentPassengers: Int { get set } // 標(biāo)記為get set练湿,可能是變量或帶有 getter 和 setter 的計(jì)算屬性
func estimateTime(for distance: Int) -> Int
func travel(distance: Int)
}
擴(kuò)展
// 擴(kuò)展允許我們給任何類型添加方法
extension String {
// Swift 的字符串有一個(gè)修剪空格和換行的方法,但它很長(zhǎng)审轮,所以我們可以將它變成一個(gè)擴(kuò)展
func trimmed() -> String {
self.trimmingCharacters(in: .whitespacesAndNewlines)
}
}
var quote = " The truth is rarely pure and never simple "
let trimmed = quote.trimmed()
// 如果您想直接更改值而不是返回新值肥哎,請(qǐng)將您的方法標(biāo)記為mutating如下所示
extension String {
mutating func trim() {
self = self.trimmed()
}
}
quote.trim()
// 擴(kuò)展還可以向類型添加計(jì)算屬性
extension String {
var lines: [String] {
self.components(separatedBy: .newlines)
}
}
let lyrics = """
But I keep cruising
Can't stop, won't stop moving
print(lyrics.lines.count) // 2
協(xié)議擴(kuò)展
// 對(duì)協(xié)議進(jìn)行擴(kuò)展
extension Collection { // Array、Dictionary和Set都符合Collection協(xié)議
var isNotEmpty: Bool {
isEmpty == false
}
}
let guests = ["Mario", "Luigi", "Peach"]
if guests.isNotEmpty {
print("Guest count: \(guests.count)")
}
可選型
// 可選值表示數(shù)據(jù)的缺失
// 它們區(qū)分值為 0 的整數(shù)和根本沒有值的整數(shù)
let opposites = [
"Mario": "Wario",
"Luigi": "Waluigi"
]
let peachOpposite = opposites["Peach"] // 特殊值nil疾渣,意味著沒有值
// Swift不允許直接使用可選型數(shù)據(jù)篡诽,因?yàn)榭赡苁强盏模晕覀冃枰忾_可選性數(shù)據(jù)才能使用它
// 查看內(nèi)部是否有值榴捡,如果有則取出并使用它
// 第一種解包方式(最常見的方式)
if let marioOpposite = opposites["Mario"] {
print("Mario's opposite is \(marioOpposite)")
}
用guard解包
// 第二種解包方式
// gurad let與if let非常相似杈女,只是邏輯顛倒過來
func printSquare(of number: Int?) {
guard let number = number else {
print("Missing input")
return
}
print("\(number) x \(number) is \(number * number)")
}
// 可以在任何條件下使用gurad,包括不解開選項(xiàng)的條件,例如防護(hù)數(shù)組為空
nil合并
// 第三種解包方式
// 在可選值為空時(shí)提供默認(rèn)值
let tvShows = ["Archer", "Babylon 5", "Ted Lasso"]
let favorite = tvShows.randomElement() ?? "None"
// nil 合并運(yùn)算符在創(chuàng)建選項(xiàng)的許多地方都很有用
let input = ""
let number = Int(input) ?? 0
print(number)
可選鏈
let names = ["Arya", "Bran", "Robb", "Sansa"]
let chosen = names.randomElement()?.uppercased() // 如果可選型內(nèi)部有值碧信,則將其解開,并......
print("Next in line: \(chosen ?? "No one")")
可選型try?
enum UserError: Error {
case badID, networkFailed
}
func getUser(id: Int) throws -> String {
throw UserError.networkFailed
}
// 當(dāng)不關(guān)心拋出了什么錯(cuò)誤時(shí)可以使用 try?街夭,只關(guān)心調(diào)用是否返回用戶
// 如果確切想知道拋出了什么錯(cuò)誤就不應(yīng)該使用try?而是使用do try catch
if let user = try? getUser(id: 23) {
print("User: \(user)")
}