字符串
字符串是一系列字符組成的。Swift字符串由String類型表示。
1.使用字符串文字作為常量或變量的初始值:
let str = "I am zhangfei"http://str 系統使用類型推斷為String類型
2.多行字符串:由三個雙引號"""
括起來的字符序列。注意:多行字符串文字的正文開始以及結束時,分隔符"""
必須獨占一行。
let quotation = """
The White Rabbit put on his spectacles. "Where shall I begin,
please your Majesty?" he asked.
"Begin at the beginning," the King said gravely, "and go on
till you come to the end; then stop."
"""
let multilineString = """
These are the same.
"""
多行字符串文字中包含換行符時,該換行符也會出現在字符串的值中。
如果只想使用換行符來簡化代碼的讀取,而不希望換行符成為字符串值的一部分,請在這些行的末尾寫一個反斜杠\
。
/*
不加反斜杠\打印:
The White Rabbit put on his spectacles. "Where shall I begin,
please your Majesty?" he asked.
"Begin at the beginning," the King said gravely, "and go on
till you come to the end; then stop."
加反斜杠\打印:
The White Rabbit put on his spectacles. "Where shall I begin,please your Majesty?" he asked.
"Begin at the beginning," the King said gravely, "and go ontill you come to the end; then stop."
*/
let softWrappedQuotation = """
The White Rabbit put on his spectacles. "Where shall I begin,\
please your Majesty?" he asked.
"Begin at the beginning," the King said gravely, "and go on \
till you come to the end; then stop."
"""
print(softWrappedQuotation)
字符串中的特殊字符
字符串中可以包含以下特殊字符:
- 轉義的特殊字符
\ 0
(空字符),\\
(反斜杠),\ t
(水平制表符),\ n
(換行符),\ r \ n
(回車符),\"
(雙引號)和\'
(單
引號)。 - 一個任意的Unicode標量值,寫為
\ u {n}
,其中n
是1-8位十六進制數。
特殊字符示例:
let name = "i am \"張飛\""
let dollarSign = "\u{24}" // $, Unicode標量 U+0024
let blackHeart = "\u{2665}" // ?, Unicode標量 U+2665
let sparklingHeart = "\u{1F496}" // ??, Unicode標量 U+1F496
print(name+dollarSign+blackHeart+sparklingHeart)//!<i am "張飛"$???
因為多行字符串文字使用三個雙引號"""
而不是一個"
,故多行字符串文字中包含雙引號"
可以不用轉義它。但是要在多行字符串中包含"""
,需要至少轉義一個引號。
let threeDoubleQuotationMarks = """
Escaping the first quotation mark \"""
Escaping all three quotation marks \"\"\"
"""
擴展字符串分隔符: 我們可以將包含特殊字符的字符串放在擴展分隔符
中,讓所包含的特殊字符(如:轉義符)不生效。使用時將字符串放在引號"
中并用數字符號#
括起來。#
的個數不限制,但是數量需要保持一致性。形式:let str = #"Line 1\nLine 2"#
,str
輸出換行符\n
而不是輸出兩行的字符串。
如果需要字符串中特殊字符的特殊效果,則需要在轉義字符\
后面使用數字符號#
,但要注意匹配#
的個數。例如,字符串:let str = #"Line 1\nLine 2"#
,我們需要讓換行符\n
生效,則可以使用let str = #"Line 1\#nLine 2"#
來代替。同樣,let str = ##"Line 1\##nLine 2"##
或let str = ###"Line 1\###nLine 2"###
也能讓換行符生效。
多行字符串使用擴展分隔符而不需要使用轉義符\
,例如:
let threeQuotationMarks = #"""
Here are three more double quotes: """
"""#
print(threeQuotationMarks)//!< log:Here are three more double quotes: """
初始化一個空的字符串: 可以使用將空字符串指定給變量,或使用初始化字符串的語法初始化一個String
實例:
// 一下兩個字符串都是空的,并且彼此都是相等的
var emptyString = ""
var anotherEmptyString = String()
字符串判空:
if emptyString.isEmpty {
print("空字符串")
}
可變字符串:將特定字符串賦值給變量或常量,來表示字符串是否可以被修改。
將特定字符串賦值給變量:在這種情況下可以對其進行修改。
var variableString = "Horse"
variableString += " and carriage"
print(variableString)
將特定字符串賦值給常量:在這種情況下無法對其進行修改。
let constantString = "Highlander"
constantString += " and another Highlander"http://!< 編譯器報錯:constantString是常量不可變
這種方法與Objective-C和Cocoa中的字符串可變不同,您可以在兩個類NSString和NSMutableString
之間進行選擇,區分可變字符串。
字符串是值類型: Swift的String
類型是一種值類型。如果我們創建一個新的字符串a
,在將a
傳遞給函數或方法時,或將其賦值給常量或變量時,將復制字符串a
的值。在以上每種情況下,都會創建現有字符串的新副本,并傳遞或分配新副本,而不是原始字符串。
Swift默認復制字符串的行為,確保了在函數或方法中傳遞字符串時,該字符串的值不會被改變,無論它來自何處,除非我們自己修改。
同時Swift的編譯器對字符串的默認復制行為做了優化:只有在絕對必要的情況下才會進行實際的復制,保證了性能。
字符使用:我們可以通過使用for-in
循環遍歷字符串來訪問字符串中各個字符。
let str = "Dog!"
for character in str {
print(character)
}
創建一個Character
類型的常量或變量
//創建常量
let character : Character = ""
print(character)
//創建變量
var character : Character = ""
character = ""
print(character)
通過字符數組,生成一個字符串
let catCharacters : [Character] = ["c","a","t","i","s",""]
let catString = String(catCharacters)
print(catString)
連接字符串和字符:
字符串可以使用加法運算符+
連接到一起以創建新的字符串:
let string1 = "hello"
let string2 = " there"
let welcome = string1 + string2
print(welcome)
使用加號賦值運算符+=
:
var instruction = "look over"
let string2 = " there"
instruction += string2 //!< log:look over there
使用String
類型的append()
方法將Character
類型的值添加到String
類型的變量。
var character : Character = ""
character = ""
var instruction = "look over"
let string2 = " there"
instruction += string2
instruction.append(character) //!< look over there
使用多行字符串文字來構建更多行的字符串,則希望字符串中的每一行都以換行符結束,包括最后一行。
let badStart = """
one
two
"""
let end = """
three
"""
/*輸出兩行:badStart的最后一行不以換行符結束,所以該行與end的第一行結合
one
twothree
*/
print(badStart + end)
let goodStart = """
one
two
"""
/*輸出三行:goodStart最后一行以換行符結束。
one
two
three
*/
print(goodStart + end)
字符串插值:字符串插值是一種通過在字符串中混合常量,變量,文字和表達式并可以構造出新字符串的方法。
作用:將常量或變量的名稱包含在較長字符串中作為占位符,并提示Swift將其替換為該常量或變量的當前值。使用形式:將名稱括在括號中,并在左括號前用反斜杠轉義它\(變量或常量)
。單行和多行字符串都可以使用字符串插值。
let multiplier = 3
let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"
print(message)//!< 3 times 2.5 is 7.5
上例中\(multiplier)
和\(Double(multiplier) * 2.5)
屬于字符串插值。
print(#"Write an interpolated string in Swift using \(multiplier)."#)//!<Write an interpolated string in Swift using \(multiplier).
上例中使用擴展字符串分隔符
來創建包含特殊字符\
的字符串,否則這些字符將被視為字符串插值。
若要在使用擴展分隔符
的字符串中使用字符串插值,需將\
后面的數字符號#
的個數與字符串開頭和結尾處#
的個數相匹配。
print(#"Write an interpolated string in Swift using \#(multiplier)."#)//!<Write an interpolated string in Swift using 3.
Unicode:又名:統一碼、萬國碼、單一碼。它是跨語言、跨平臺進行文本轉換、處理的國際標準。Swift中的字符串和字符類型完全符合Unicode。
Unicode標量
:Swift的原生String
類型是根據Unicode標量構建的。Unicode標量:使用21個二進制位表示的字符或修飾符,(注解:目前Unicode的編碼范圍達到了21位,Unicode標量范圍 0x0000 - 0x10ffff 的范圍,二進制位為 1 0000 1111 1111 1111 1111,總共21位)例如:U+0061
表示a
,U+1F425表示??
。需要注意的是,Unicode標量值并不需要把所有21個二進制位都分配給字符或修飾符 ,某些多出來的Unicode標量會保留下來,用于將來分配或用于UTF-16編碼(注解:UTF-16是Unicode的其中一個使用方式,即把Unicode字符集的抽象碼位映射為16位的序列,用于數據存儲或傳遞)。擴展字形集群:Swift的
Character
類型的每個實例,代表一個擴展的字形集群。擴展字形集群是一個或多個可組合的Unicode標量(組合時,產生單個人類可讀字符)的序列。字母é
可以表示為單個Unicode標量\u{00E9}
。字母é
也可以表示為一對標量 :標準字母e
:\u{0065}
和尖音符\u{301}
組合的形式。(音調符標量以圖形方式應用于其前面的標量,當它由具有Unicode感知的文本渲染系統渲染時將e轉換為é)
在這兩種情況下,字母é
表示為單個Swift中的Character
值,表示可擴展的字形簇。在第一種情況下,集群中的單個標量;在第二種情況下,它是兩個標量的集群:
let eAcute: Character = "\u{E9}" // é
let combinedEAcute: Character = "\u{65}\u{301}" //é
print(String(eAcute)+String(combinedEAcute))
可擴展的字形集群是一種將許多復雜腳本字符表示為單個字符值的靈活方式。
let precomposed: Character = "\u{D55C}" // ?
let decomposed: Character = "\u{1112}\u{1161}\u{11AB}" // \u{1112}:?, \u{1161}:?,\u{11AB}: ? ->?
print(String(precomposed)+String(decomposed))
區域指示符號的Unicode標量可以成對組合以生成單個字符值,例如區域指示符符號U(U + 1F1FA)和區域指示符符號字母S(U + 1F1F8)的組合:
let regionalIndicatorForUS: Character = "\u{1F1FA}\u{1F1F8}"
print(String(regionalIndicatorForUS))//log:????
字符計數:檢索字符串中字符的數目,可以使用字符串的count屬性:
let title = "Koala ??, Snail ??, Penguin ??, Dromedary ??"
print("title中有\(title.count)個字符")//!< 40個字符
需要注意的是:Swift中對字符串拼接擴展字形集群可能并不會影響字符串的字符數目。如:
var x = "thing" //!< x.count = 5
x += "\u{301}" //!< x:thin?
print(x) //!< x.count 依舊是5
擴展的字形集群可以由多個Unicode標量組成。這意味著相同字符的不同表示可能需要不同的內存量來存儲。因此,在Swift中,字符串的每個字符在內存中所占的大小可能不相同。需要注意的是如果字符串特別長,使用count
屬性獲取字符串中字符數量時,是會遍歷整個字符串中的Unicode標量的。count
屬性可能與包含相同字符的NSString的length
屬性返回的字符數量不相同。因為兩者的計算基準不一樣。NSString的長度基于字符串的UTF-16
表示中的16位碼元的數量,而不是基于字符串中Unicode可擴展的字形集群的數量。
//OC中計算的字符數。
NSString *str = @"Koala ??, Snail ??, Penguin ??, Dromedary ??";
NSLog(@"%ld",str.length);//!< 44個字符
訪問和修改字符串:通過相應方法和屬性或使用下標語法來訪問和修改字符串。
字符串索引:每個String值都有一個關聯的索引類型String.Index
,它對應于字符串中每個字符的位置。
如上所述,Swift中不同的字符可能需要不同的內存量來存儲,因為Swift的字符串中字符數是基于Unicode標量的
來計算的:a.集群中的單個標量,b.多個標量的可擴展集群。因此Swift字符串不能用整數值索引,為了確定某個特定的字符位于哪個位置,我們必須從該字符串的開頭或結尾遍歷每個Unicode標量
。
使用startIndex
屬性可以訪問字符串的第一個字符的位置。endIndex
屬性是字符串最后一個字符之后的位置。因此,endIndex
屬性不是字符串下標的有效參數。如果字符串為空,則startIndex
和endIndex
相等。可以使用字符串的索引index(before: )
和index(after:)
方法訪問給定索引之前和之后的索引。要訪問遠離給定索引的索引,可以使用索引index(_:, offsetBy: )
方法,而不是多次調用其中一種方法。字符串title
根據字符索引獲取字符:title[String.Index(必須是索引類型)]
let title = "Koala ??, Snail ??, Penguin ??, Dromedary ??"
let subStr = title[title.index(after: title.startIndex)]//!< startIndex之后的位置 輸出o
let subStr1 = title[title.index(before: title.endIndex)]//!< ??
let subStr2 = title[title.index(title.endIndex, offsetBy: -1)] //!< log:??
let subStr3 = title[title.index(title.startIndex, offsetBy: 6)]//!< log: ??
let index = title.index(title.startIndex, offsetBy: 15)
let subStr4 = title[index] //!< log:??
嘗試訪問字符串范圍之外的索引或字符時將觸發運行時錯誤。
//! 所得索引超越了字符串的有效范圍,觸發運行時錯誤:Thread 1: Fatal error: String index is out of bounds
let outsideIndex = title.index(after: title.endIndex)
//!索引超越了有效范圍,觸發運行時錯誤:Thread 1: Fatal error: String index is out of bounds
let subStr5 = title[title.endIndex]
使用indices
屬性可以獲取字符串中所有字符的索引。
let indices = title.indices;//!DefaultIndices<String>(_elements: "Koala , Snail , Penguin , Dromedary ", _startIndex: Swift.String.Index(_rawBits: 0), _endIndex: Swift.String.Index(_rawBits: 3407872))
var tempStr:String = ""
for index in indices {
print("\(title[index])","",separator: "_", terminator: "", to: &tempStr)
}
////!< 最終合成的新字符串:K_o_a_l_a_ __,_ _S_n_a_i_l_ __,_ _P_e_n_g_u_i_n_ __,_ _D_r_o_m_e_d_a_r_y_ __
print("最終合成的新字符串:\(tempStr)")
重點:我們可以在符合Collection協議的任何類型上使用startIndex
和endIndex
屬性以及索引index(before: )
和index(after:)
和index(_:, offsetBy: )
方法。這包括字符串以及集合類型,如Array,Dictionary和Set。
字符串插入和刪除:
插入:
字符串指定索引處插入單個字符使用insert(_:at:)
方法;在指定索引處插入另一個字符串使用insert(contentsOf:at:)
方法。
var inserStr = "hello"
//! 插入單個字符:unicode標量
inserStr.insert("\u{1F1F7}", at: inserStr.startIndex)//!< log:??hello
//! 插入單個字符:普通字符
inserStr.insert("!", at: inserStr.endIndex)//!< log:??hello! 插入時可以使用endIndex
//!< 插入字符串:由字符:unicode標量組成的字符串
let scalarStr = "\u{1F1F6}\u{1F496}"http://!< ????
inserStr.insert(contentsOf: scalarStr, at: inserStr.startIndex)//!< ??????hello!
//! 插入普通字符串:
let normalStr = "_word"
inserStr.insert(contentsOf: normalStr, at: inserStr.index(before: inserStr.endIndex))//!< ??????hello_word!
刪除:
字符串刪除指定索引處的單個字符使用remove(at:)
方法;刪除指定范圍內的子字符串使用removeSubrange(_:)
方法:
//復雜組成的字符串
var removeStr = "\u{1F1F6}\u{1E67F}\u{1F496}\u{1F1F7}hello_word!eye\u{301}"http://!< log:??????hello_word!eyé
//移除unicode標量字符:??
removeStr.remove(at: removeStr.index(removeStr.startIndex, offsetBy: 2))//!< log:????hello_word!eyé
//移除普通字符:y 為啥-2因為endIndex屬性表示字符串最后一個字符之后的位置
removeStr.remove(at: removeStr.index(removeStr.endIndex, offsetBy: -2))//!< log:????hello_word!eé
//!< 刪除子0-1范圍內的字符串:由字符:unicode標量組成的子字符串:??
//*range
// let range = removeStr.startIndex..<removeStr.index(removeStr.startIndex, offsetBy: 2)
//或
let range = removeStr.startIndex...removeStr.index(removeStr.startIndex, offsetBy: 1)
removeStr.removeSubrange(range) //!< ??hello_word!eé
注意:String
類型實現了RangeReplaceableCollection
協議,其他實現了RangeReplaceableCollection
協議的任何類型都可以使用insert(_:at:)
,insert(contentsOf:at:)
,remove(at:)
和removeSubrange(_:)
方法。如:Array,Dictionary和Set。
子字符串:
從字符串中獲取子字符串時 - 例如,使用索引或類似prefix(_:)
的方法 ,結果是Substring
的實例,而不是另一個字符串。Swift中的子字符串與字符串具有多數相同的方法,這意味著我們可以像處理字符串一樣使用子字符串。但是與字符串不同,我們在對字符串執行操作時只會使用子字符串很短的時間。當我們需要將子字符串存儲更長時間時,則需要將子字符串轉換為String
實例。
var myString = "\u{1F1F6}\u{1E67F}\u{1F496}\u{1F1F7}hello_word!eye\u{301}"http://!< log:??hello_word!eyé
//從字符串中取出hello子字符串
//1.獲取hello在字符中的范圍
//Returns the last index where the specified value appears in the collection.
let subStart = myString.lastIndex(of:"??" ) ?? myString.startIndex //!< 字符??的位置
//Returns the first index where the specified value appears in the collection.
let subEnd = myString.firstIndex(of: "_") ?? myString.endIndex//!< 字符_的位置
//2.獲取子字符串
let subString = myString[subStart..<subEnd]//!<log: ??hello
print(subString)
//3.若需要長時間使用子字符串則需要類型轉換
let longSubStr = String(subString) //!< or:String.init(subString)
重點知識:
字符串和子字符串之間的區別:與字符串一樣,每個子字符串都有一個內存區域,用于存儲構成子字符串的字符。但是作為性能優化,子字符串可以重用用于存儲原始字符串的部分內存,或者用于存儲另一個子字符串的內存的一部分。字符串具有類似的優化,但如果兩個字符串共享內存,則它們是相等的
此性能優化意味著在修改字符串或子字符串之前,不會增加復制內存的性能成本。如上所述,子字符串不適合長期存儲 因為它們重用原始字符串的存儲,只要使用任何子字符串,整個原始字符串就必須保存在內存中
。
示例描述:myString是一個字符串,這意味著它有一個內存區域,用于存儲構成字符串的字符。因為subString是myString的子字符串,所以它重用了myString使用的內存。相比之下,longSubStr是一個字符串 ,從子字符串創建時,它有自己的存儲空間。
字符串比較:
字符串和字符是否相等的比較:使用“等于”運算符==
和“不等于”運算符!=
檢查字符串和字符相等性。
let testStr1 = "i have a cat\u{E9}?"http://!< i have a caté?
let testStr2 = "i have a cat\u{65}\u{301}?"http://!< i have a caté?
if testStr1 == testStr2 {
print("這兩個字符串是相等的")
}
如果兩個字符串值(或兩個字符值)的擴展字形集群在規范上等效,則它們被認為是相等的。如果擴展的字形集群具有相同的語言含義和外觀,則它們在規范上是等效的,即使它們是不同Unicode標量
組成的。
舉個反例:英語中大寫字母A:\u{0041}
不等同于俄語中的A:\u{0410}
。字符在視覺上相同,但卻不具有相同的語言含義,因此也是不相等的。
let englishA = "\u{0041}"http://!< A
let RussianA = "\u{0410}"http://!< A
if englishA == RussianA {
print("這兩個字符串是相等的")
} else {
print("這兩個字符串是不相等的")//!< log:這兩個字符串是不相等的
}
字符串的前綴與后綴的比較:要檢查字符串是否具有特定的字符串前綴或后綴,調用字符串的hasPrefix(_ :)
和hasSuffix(_ :)
方法,返回值都為布爾值。
let testStr1 = "i have a cat\u{E9}?"http://!< i have a caté?
let testStr2 = "i have a cat\u{65}\u{301}?"http://!< i have a caté?
let array = [testStr1,testStr2]
for item in array[...] {
if item.hasPrefix("i") {
print(item + "*")
}
}
/*注意:hasPrefix(_ :)和hasSuffix(_ :)方法在每個字符串中的擴展字形集群之間執行逐個字符的規范等效比較。*/
for item in array[...] {
if item.hasSuffix("\u{E9}?") {
print(item + "*")//!<輸出兩次: i have a caté?*
}
}
注意:在每個字符串中調用hasPrefix(_ :)
和hasSuffix(_ :)
方法,會在字符串的擴展字形集群之間逐個字符進行規范的相等比較
字符串的Unicode表示:
將Unicode字符串寫入文本文件或其他存儲時,字符串中的Unicode標量
將以多種Unicode定義的編碼方式之一進行編碼。每種編碼方式都是以碼元(二進制位)為單位對字符串進行編碼。
Unicode定義的編碼方式:1.UTF-8
編碼格式:將字符串編碼為多個8個二進制位的碼元。2.UTF-16
編碼格式:將字符串編碼為多個16個二進制位的碼元。3.UTF-32
編碼格式:將字符串編碼為多個32個二進制位的碼元。
Swift提供了幾種訪問字符串的Unicode的方法。
a. 使用for-in
語句迭代字符串,將其各個字符值作為Unicode擴展字符集群進行訪問。
b. 訪問字符串的值依據兼容Unicode的三種編碼方式之一。
- UTF-8碼元的集合,使用字符串的
utf8
屬性訪問 - UTF-16碼元的集合,使用字符串的
utf16
屬性訪問 - 21位的Unicode標量值的集合,相當于字符串的UTF-32編碼格式,使用字符串的
unicodeScalars
屬性訪問。
1.UTF-8表示:
通過迭代字符串的utf8
屬性來訪問字符串的UTF-8編碼格式的表示形式。utf8
屬性的類型為String.UTF8View
。
關于String.UTF8View
結構體:將字符串內容作為UTF-8碼元的集合進行展示。我們可以使用字符串utf8
屬性訪問字符串的UTF-8碼元表示形式。String.UTF8View
將字符串的Unicode標量值
編碼為無符號的8位整數,故:String.UTF8View
是無符號的8位整數UInt8
值的集合 。字符串中Unicode標量
值最長可達21位。要使用8位整數表示這些標量值,通常需要多個UTF-8代碼單元。
let flowers = "Flowers ??"
for v in flowers.utf8 {
print(v,"",separator: " ", terminator: "")//替換換行符
}
//!< 控制臺最終輸出:70 108 111 119 101 114 115 32 240 159 146 144
/*一個??的字符是unicode標量:\u{1F490}
flowermoji.unicodeScalars :32位的0001F490 表示字符為\u{1F490} 打印值為:128144
*/
let flowermoji = "??"
let flowermojiUnicodeScalars = flowermoji.unicodeScalars //!< log:"\u{0001F490}" 這個是封包了
for v in flowermojiUnicodeScalars {
print(v,v.value)//!< v.value = 128144 9*16 + 4*256 +15 * 256 *16 + 256 *256 = 128144
}
//將??unicode標量:\u{128144},轉為UTF-8編碼集合,會發現需要多個
var count = 0
var value = ""
for v in flowermoji.utf8 {
count += 1
value += "\(v) "
}
//!console.log:??unicode標量轉換成了4個utf8碼元集合分別是:240 159 146 144
print("\u{1F490}unicode標量轉換成了\(count)個utf8碼元集合分別是:\(value)")
比如let dogString = "Dog???"
轉換UTF-8
集合"68 111 103 226 128 188 240 159 144 182 "
2.UTF-16表示:
通過迭代字符串的utf16
屬性來訪問字符串的UTF-16編碼格式的表示形式。utf16
屬性的類型為String.UTF16View
,與String.UTF8View
同理。區別:String.UTF16View
是無符號的16位整數UInt16
值的集合 。字符串中Unicode標量
值最長可達21位。要使用16位整數表示這些標量值,可能需要兩個UTF-16代碼單元。
let dogString = "Dog???"
var count = 0
var value = ""
for v in dogString.utf16 {
count += 1
value += "\(v) "
}
//控制臺輸出: ?? unicode標量轉換成了6個utf16碼元集合分別是:68 111 103 8252 55357 56374
print("\u{1F436}unicode標量轉換成了\(count)個utf16碼元集合分別是:\(value)")// ?? :\u{1F436}
3.Unicode Scalar 表示:
通過迭代字符串的unicodeScalars
屬性來訪問字符串的Unicode標量表示形式(集合)。unicodeScalars
屬性的類型為String.UnicodeScalarView
。每個UnicodeScalar
都有一個value屬性: Unicode.Scalar的實例對象,會使用無符號的32位整數UInt32
,返回標量的值。
for scalar in dogString.unicodeScalars {
print("\(scalar.value) ", terminator: "")// log "68 111 103 8252 128054 "
}
參考資料:
swift 5.1官方編程指南
推薦文章:
用Flutter 寫一個簡單頁面
5分鐘,帶你迅速上手Markdown語法
Swift 5.1 (2) - 運算符
Swift 5.1(1) - 基礎
iOS UI狀態保存和恢復(三)
iOS UI狀態保存和恢復(二)
iOS UI狀態保存和恢復(一)
iOS 中精確定時的常用方法
Sign In With Apple(一)