此文章屬于Swift 基礎(chǔ)教程处窥,主要是全面的了解一下Swift的各種語法和函數(shù)破婆。
主要參考Swift文檔中的快速預(yù)覽模塊匈挖,期間搜索了最新的資料整理兄猩,加入了一些關(guān)鍵字的討論和確認。希望對你的學(xué)習(xí)有幫助半开。
如果有你的觀點和想法想和我討論隔披,歡迎留言。
github 地址
建議整體復(fù)制到你的playGround 運行
import UIKit
// 新語言的第一節(jié) hello world
let helloWorld = "hello world!"
print(helloWorld)
//使用let 做常量 var 做變量 編譯器可以判斷值的類型 也可指定其類型 但是不會隱式的轉(zhuǎn)換成其他類型
let myNumber = 43
var mynumber01 = 45
mynumber01 = 46
let myNumber3: Double = 90
let label = "The width is "
let width = 99
let widthString = label + String(width)
let widthString01 = "The width is \(width)"
let widthString02 = "The width is \(mynumber01 + width) km"
//數(shù)值型字面量也可以增加額外的格式使代碼更加易讀寂拆。整數(shù)和浮點數(shù)都可以添加額外的零或者添加下劃線來增加代碼的可讀性奢米。下面的這些格式都不會影響字面量的值。
let paddedDouble: Float = 000123.456
let oneMillion = 1_000_000
let justOverOneMillion = 1_000_000.000_000_1
//""" 用于多行字符串 以下列出了兩種換行方式 需要注意的是:使用"""換行方式 不能和內(nèi)容在同一行 否則會報錯
let lineString = """
你好
我現(xiàn)在
不方便
去你那
請多包涵
"""
let lineString1 = "你好\n我現(xiàn)在\n不方便\n去你那"
//創(chuàng)建數(shù)組和字典 根據(jù)規(guī)范 最好漓库,后留出一個空格 :后留出一個空格
//在字典中如果類型不一致 或者無法判斷出類型恃慧,需要對其進行注釋,例如 : [String: Any]
/*
知識點:Any渺蒿、AnyHashable痢士、AnyObject、AnyClass的區(qū)別
Any是一個空協(xié)議集合的別名茂装,它表示沒有實現(xiàn)任何協(xié)議怠蹂,因此它可以是任何類型,包括類實例與結(jié)構(gòu)體實例少态,以及函數(shù)類型和可選類型城侧。
AnyHashable遵守Hashable協(xié)議的Any類型,是Any的子集合彼妻,主要用于Dictionary和Set中嫌佑。(Dictionary 要求它的Key類型需要遵守 Hashable協(xié)議)
AnyObject是一個成員為空的協(xié)議,任何對象都實現(xiàn)了這個協(xié)議侨歉。它是Any的子集合屋摇,Any中的類實例。
AnyClass是AnyObject.Type的別名而已幽邓。
可參考:https://blog.csdn.net/feosun/article/details/78002558
*/
var newArray = ["one", "two", "three", "four"]
//根據(jù)下標(biāo) 修改元素
newArray[1] = "nihao"
//添加元素
newArray.append("nibuhao")
var newDic: [AnyHashable: Any] = [
"name": "xiaoming",
"age": 88,
88: 89,
]
newDic[88] = 999
//創(chuàng)建空數(shù)組或者字典,如果可以推斷用戶信息炮温,則可設(shè)置為空數(shù)組或者空字典
var emptyArray = [String]() //標(biāo)明元素類型
let emptyArray1 = [] as [String]
emptyArray = []
var emptyDic = [String: Any]()
let emptyDic1 = [:] as [String: Any]
emptyDic = [:]
let acores = [78,89,99,23,34,54,65]
var teamScore = 0
for score in acores {
if score > 50 {
teamScore += 3
} else {
teamScore += 1
}
}
print(teamScore)
//在值的類型后加? 表示類型可選
var optionString: String? = "optionstring"
print(optionString == nil)
var optionName: String? = "fengfeng"
var greeting: String = "hello!"
if let n = optionName {
greeting = "hello \(n)"
} else {
print("name 是空的")
}
//處理可選值的另一種方法是使用牵舵?柒啤? 提供默認值
let chaoName1: String? = nil
let chaoName: String = "lichao"
let chao = "hello \(chaoName1 ?? chaoName)"
//switch 支持任意類型的數(shù)據(jù)的操作,不限于整數(shù)和相等的情況. 下面例子中的where關(guān)鍵字指定額外的要求畸颅,并且只能在使用switch的語句担巩,所有這些vagateble是泛型的,免去Swift中的類型轉(zhuǎn)換没炒。
//關(guān)于泛型可以參考(http://www.reibang.com/p/6624f5365745)比較重要
let vagateble = "daxiang"
switch vagateble {
case "dayali":
print("shuiguoshi _ dayali")
case "pingguo":
print("shuiguoshi _ pingguo")
case "juzi":
print("shuiguoshi _ juzi")
case let x where x.hasPrefix("daxiang") :
print("shuiguoshi _ daxiangjiao+++++++ \(x)")
default:
print("shadoubushi")
}
//字典的迭代 iterate (不同類型的數(shù)字是不能比較大小的兵睛,比如Double 和 Int ,需要有一個轉(zhuǎn)換為相同類型才可以比較,這也是swift 安全性的體現(xiàn)之一)
let iterateDic = [
"one": [2,3,4,67,78.8766,432],
"two": [2,3,4,67,78.8766,432],
"three": [2,3,4,67,78.8766,432],
"four": [2,3,4,67,78.8766,432],
"five": [2,3,4,67,78.8766,432],
]
var lagest: Double = 0
for (_, values) in iterateDic {
for value in values {
if value > lagest {
lagest = value
}
}
}
print(lagest)
//while repeat...while
var whileNumber = 2
while whileNumber < 200 {
whileNumber += 33
}
print(whileNumber)
var repeatNumber = 3
repeat {
repeatNumber += 20
} while repeatNumber < 300
print(repeatNumber)
//..< 不包括上限的值 ... 包括上限的值
var total = 0
for i in 1..<3 {
total += i
}
print(total)
//函數(shù)和閉包
func greet(person: String, day: String) -> String {
return "hello \(person) ,today is \(day)"
}
greet(person: "liuchao", day: "2018.9.27")
//在參數(shù)名前寫入自定義的參數(shù)標(biāo)簽(本例的at) 或者加 _ 可省略參數(shù)標(biāo)簽
func greet2(_ person: String, at day: String) -> String {
return "hello \(person) ,today is \(day)"
}
greet2("liuchao", at: "2018.9.27")
// 同objectiveC相比祖很,swift多了一種結(jié)構(gòu)類型笛丙,就是元組(之后會講)
// 函數(shù)可使用元組 傳
入復(fù)合參數(shù)
func jisuanscores(scores: [Int]) -> (min: Int, max: Int, sum: Int) {
var min = scores[0]
var max = scores[0]
var sum = 0
for score in scores {
if score > max {
max = score
} else if score < min {
min = score
}
sum += score
}
return (min, max, sum)
}
let result = jisuanscores(scores: [3,45,66,77,23,35,546,243,37])
print(result.min, result.max, result.sum)
//函數(shù)還可以嵌套
func returnFifteen() -> Int {
var a = 10
func add() {
a += 5
}
add() //內(nèi)部函數(shù)的調(diào)用需要在函數(shù)聲明之后
return a
}
returnFifteen()
//牛逼的是 函數(shù)還可以返回另一個函數(shù)作為返回值
func fanHuiHanShu() -> ((Int) -> Int) {
func addNumber(number: Int) -> Int {
return number + 23
}
return addNumber
}
let addNumber = fanHuiHanShu()
addNumber(33)
//既然函數(shù)可以作為返回值 那么函數(shù)同樣可以作為參數(shù)之一
func jianCeShiFouYouShiYiXia(list: [Int], condition: (Int) -> Bool) -> Bool {
for number in list {
if condition(number) {
return true
}
}
return false
}
let list = [2,3,4,5,6,7,23,43]
func lessThanTen(number: Int) -> Bool {
return number < 10
}
jianCeShiFouYouShiYiXia(list: list, condition: lessThanTen)
//閉包closures 閉包是無名的,因為他們能夠從上下文中捕獲變量假颇、常量胚鸯,從而應(yīng)用在自身的作用區(qū)域。
let number0 = list.map({ (number: Int) -> Int in
let result = 3 * number
return result
})
print(number0)
print(list)
//還可以這樣寫笨鸡, 當(dāng)已知閉包的類型(例如委托的回調(diào))時姜钳,可以省略其參數(shù)的類型,返回類型或兩者形耗。 單個語句閉包隱式返回其唯一語句的值哥桥。
let number1 = list.map( { number in
3 * number
})
print(number0)
print(list)
//您可以按編號而不是按名稱來引用參數(shù) - 這種方法在非常短的閉包中特別有用。
//作為函數(shù)的最后一個參數(shù)傳遞的閉包可以在括號后面立即出現(xiàn)激涤。
//當(dāng)閉包是函數(shù)的唯一參數(shù)時拟糕,可以完全省略括號。
let sortedNumbers = list.sorted { $0 > $1 }
print(sortedNumbers)
//閉包的聲明
var biBao: () -> String = {
return "nihao"
}
//調(diào)用
biBao()
//無返回值的閉包
var biBao2: () -> () = {
print("wobuhao")
}
biBao2()
//帶參數(shù)的閉包
var canShuBiBao: (String, Int) -> String = {
(name: String, age: Int) -> String in
let nameString = "我叫 \(name), 今年\(age)歲了倦踢!"
return nameString
}
print(canShuBiBao("liuchao",89))
//帶參數(shù)的閉包簡化 根據(jù)參數(shù)自動推斷參數(shù)類型
canShuBiBao = {
(name,age) in
let nameString = "我叫 \(name), 今年\(age)歲了送滞!"
return nameString
}
print(canShuBiBao("liuchao001",89))
//第二次閉包簡化 如果函數(shù)體只包含一句return 可省略return
canShuBiBao = {
(name,age) in
"我叫 \(name), 今年\(age)歲了!"
}
print(canShuBiBao("liuchao00333",89))
//第三次簡化 被捕獲的參數(shù)列表中 可通過 $ 獲取 可自行判斷出參數(shù)類型 所以可以省略 (name,age) in
canShuBiBao = {
"我叫 \($0), 今年\($1)歲了辱挥!"
}
print(canShuBiBao("liuchao0033333333",89))
//對象和類 (: NSObject 可省略 )
class Person: NSObject {
var name: String = "liuchao"
let age: Int = 28
var newName: String? {
// set {
// print(newValue)
// }
willSet {
print(newValue ?? "")
}
didSet {
print(oldValue ?? "")
}
// get {
// return "new liuchao name"
// }
}
init(name: String) {
self.name = name
super.init()
}
func nameAgeString() -> String {
return "我叫 \(name), 今年\(age)歲了犁嗅!"
}
deinit {
print("對象銷毀")
}
}
let person = Person.init(name: "liuchao00999999")
person.name
person.age
person.newName = "newvalue liuhao------------"
person.newName
let nageAgeString = person.nameAgeString()
//枚舉和結(jié)構(gòu)體
//使用該rawValue屬性可以訪問枚舉的原始值
enum LiuChao: Int {
case abc = 1
case two, three, four, five, six, seven
case liuchao1, liuchao2, liuchao3
func jianDanGuoLv() -> String {
switch self {
case .abc:
return "001"
case .two:
return "002"
case .three:
return "003"
case .liuchao1:
return "004"
case .liuchao2:
return "005"
case .six:
return "006"
case .four:
return "007"
default:
return "------"
}
}
}
let chao222 = LiuChao.abc.rawValue
let chao2242 = LiuChao.liuchao1.rawValue
LiuChao.abc.jianDanGuoLv()
if let row = LiuChao.init(rawValue: 3) {
row.jianDanGuoLv()
}
//枚舉的另一種情況
enum ServerResponse {
case result(String, String)
case failure(String)
}
let success = ServerResponse.result("6:00 am", "8:09 pm")
let failure = ServerResponse.failure("Out of cheese.")
switch success {
case let .result(sunrise, sunset):
print("Sunrise is at \(sunrise) and sunset is at \(sunset).")
case let .failure(message):
print("Failure... \(message)")
}
//用 typealias 關(guān)鍵字定義類型別名。一旦為類型創(chuàng)建了一個別名晤碘,你就可以在任何使用原始名字的地方使用這個別名褂微。
typealias AudioSample = UInt16
//結(jié)構(gòu)體
struct LiuChao333 {
var name: String
var age: Int
func nameAgeStringResult() -> String {
return "\(name),\(age)"
}
}
let naage = LiuChao333.init(name: "liuchao", age: 23)
naage.nameAgeStringResult()
//Protocols and Extensions 針對結(jié)構(gòu)體和枚舉 實例方法中修改屬性值,可以在方法定義前添加關(guān)鍵字mutating
protocol ExampleProtocol {
var simpleDescription: String { get }
mutating func adjust()
}
class SimpleClass: ExampleProtocol {
var simpleDescription: String = "this is a simple description"
func adjust() {
simpleDescription += "yes yes yes"
}
}
let simpaleclass = SimpleClass()
simpaleclass.adjust()
simpaleclass.simpleDescription
struct SimpleStructure: ExampleProtocol {
var simpleDescription: String = "A simple structure"
var anotherProperty: Int = 69105
mutating func adjust() {
simpleDescription += " (adjusted)"
}
}
var b = SimpleStructure()
b.adjust()
let bDescription = b.simpleDescription
extension Int: ExampleProtocol {
var simpleDescription: String {
return "The number \(self)"
}
mutating func adjust() {
self += 42
}
}
print(7.simpleDescription)
let protocolValue: ExampleProtocol = b
print(protocolValue.simpleDescription)
//print(protocolValue.anotherProperty)
// 錯誤處理
enum PrinterError: Error {
case outOfPaper
case onToner
case onFire
}
//如果在函數(shù)中拋出錯誤 函數(shù)會立刻返回 調(diào)用函數(shù)會提示錯誤
func send(job: Int, toPrinter printerName: String) throws -> String {
if printerName == "funnys" {
throw PrinterError.outOfPaper
}
return "嘿嘿 不是我"
}
try send(job: 3, toPrinter: "fundnys")
//在do 內(nèi)放可能引發(fā)錯誤的代碼 catch 內(nèi)可以打印錯誤的名字
do {
try send(job: 3, toPrinter: "funny")
} catch let printerError as PrinterError {
print(printerError)
}
//處理錯誤的另一種方式是try园爷?將結(jié)果轉(zhuǎn)為可選的宠蚂,
let printerResult = try? send(job: 2, toPrinter: "funnys")
print(printerResult ?? "dede")
//先fridgeIsOpen = true,然后是函數(shù)體正常的流程腮介,最后在 return 之前執(zhí)行 fridgeIsOpen = false,defer一個很適合的使用場景就是用來做清理工作
var fridgeIsOpen = false
let fridgeContent = ["milk", "eggs", "leftovers"]
func fridgeContains(_ food: String) -> Bool {
fridgeIsOpen = true
defer {
fridgeIsOpen = false
}
let result = fridgeContent.contains(food)
return result
}
fridgeContains("milk")
print(fridgeIsOpen)
//泛型,在尖括號里寫一個名字來創(chuàng)建一個泛型函數(shù)或者類型端衰。適用于類叠洗,枚舉和結(jié)構(gòu)體
func repeatItem<Item>(repeating item: Item, numberOfTimes: Int) -> [Item] {
var result = [Item]()
for _ in 0..<numberOfTimes {
result.append(item)
}
return result
}
repeatItem(repeating: "ItemItems", numberOfTimes: 4)
//重新實現(xiàn) Swift 標(biāo)準(zhǔn)庫中的可選類型
enum OptionalValue<Wrapped> {
case none
case some(Wrapped)
}
var possibleValue: OptionalValue<Int> = .none
possibleValue = .some(100)
//where 一般用作條件判斷,確認實現(xiàn)了什么才執(zhí)行函數(shù)體旅东,比如下面灭抑,確認T.Element實現(xiàn)了 Equatable協(xié)議,并且T.Element == U.Element
//T.Element 表示序列元素的類型 比較的是元素的類型相等 比如[1, 2, 3]的元素類型是 Int
func anyCommonElements<T: Sequence, U: Sequence>(_ lhs: T, _ rhs: U) -> Bool
where T.Element: Equatable, T.Element == U.Element
{
for lhsItem in lhs {
for rhsItem in rhs {
if lhsItem == rhsItem {
return true
}
}
}
return false
}
anyCommonElements([1, 2, 3], [3])
//元組
let http404Error = (404,"Not Found")
http404Error.0
http404Error.1
//必須元素的數(shù)量一致
let (statusCode,statusString) = http404Error
print(statusCode)
print(statusString)
let (statusCode1,_) = http404Error
//也可以單獨命名,但是必須通過訪問名字來獲取元素
let httpError1 = (statuscode2: 200, statusString2: "OK")
httpError1.statuscode2
httpError1.statusString2
//斷言,可在debug模式下運行抵代,在release模式下不運行
let age = -3
assert(age >= 0, "A person's age cannot be less than zero")
//針對代碼已經(jīng)檢查了條件
assertionFailure(_:file:line:)
//先決條件 precondition腾节,在debug和release下都運行
precondition(index > 0, "Index must be greater than zero.")
//針對代碼已經(jīng)檢查了條件
preconditionFailure(_:file:line:)
//fatalError函數(shù)一定會終止執(zhí)行,不管在什么情況下都會
fatalError(_:file:line:)