swift基本語法

YES

  • 2014WWDC發(fā)布

常量和變量使用注意

  • 在實際過程中,建議先定義常量,如果需要修改再改變?yōu)樽兞?更加安全)
  • 可以在一行中聲明多個常量或者多個變量,用逗號隔開
var x = 0.0, y = 0.0, z = 0.0
var red, green, blue: Double

類型標注

  • 如果要添加類型標注,需要在常量或者變量名后面加上一個冒號和空格,然后加上類型名稱
  • 如果你需要使用與Swift保留關(guān)鍵字相同的名稱作為常量或者變量名,你可以使用反引號(`)將關(guān)鍵字包圍的方式將其作為名字使用。無論如何,你應(yīng)當避免使用關(guān)鍵字作為常量或變量名,除非你別無選擇

整數(shù)范圍

  • 你可以訪問不同整數(shù)類型的 min 和 max 屬性來獲取對應(yīng)類型的最小值和最大值:
  • 即使是在32位平臺上,Int 可以存儲的整數(shù)范圍也可以達到 -2,147,483,648 ~ 2,147,483,647 ,大多數(shù)時候這已經(jīng)足夠大了

浮點數(shù)

  • Double精確度很高,至少有15位數(shù)字,而Float只有6位數(shù)字。選擇哪個類型取決于你的代碼需要處理的值的范圍,在兩種類型都匹配的情況下,將優(yōu)先選擇 Double。
  • 整數(shù)和浮點數(shù)都可以添加額外的零并且包含下劃線,并不會影響字面量:
let paddedDouble = 000123.456
let oneMillion = 1_000_000
let justOverOneMillion = 1_000_000.000_000_1
  • 通常來講,即使代碼中的整數(shù)常量和變量已知非負,也請使用Int類型
  • 當用這種方式來初始化一個新的整數(shù)值時,浮點值會被截斷。也就是說 4.75 會變成 4,-3.9 會變成 -3。

類型推倒

  • swift屬于強類型語言,任何一個標示符都有明確的類型
  • 如果定義一個標示符時有直接進行賦值,那么標示符后面的類型可以省略,因為swift有類型推導(dǎo),會自動根據(jù)后面的賦值來決定前面標示符的數(shù)據(jù)類型
  • option + 鼠標左鍵 可以查看變量類型

類型別名

  • 類型別名(type aliases)就是給現(xiàn)有類型定義另一個名字。你可以使用typealias關(guān)鍵字來定義類型別名

輸出常量和變量

  • Swift 用字符串插值(string interpolation)的方式把常量名或者變量名當做占位符加入到長字符串中,Swift 會用當前常量或變量的值替換這些占位符。將常量或變量名放入圓括號中,并在開括號前使用反斜杠將其轉(zhuǎn)義

基本運算

  • 沒有隱式轉(zhuǎn)換,必須保證類型一致

邏輯分支

  • if else
  • if 后面的小括號可以省略
  • 判斷句必須有明確的真假
  • 三目運算符 與OC 形同
  • switch 語句
  • switch后面的小括號可以省略
  • case語句結(jié)束后的break也可以省略
  • 如果需要穿透可以在case 語句后面跟上fallthrough
  • case后面可以判斷多個條件,用 逗號 分隔
  • switch可以判斷浮點型 字符串
  • switch 可以判斷區(qū)間 開區(qū)間 0..<10 不包括 10 0...10 包括10

for循環(huán)

  • forin
for i in 0..<10{
print(i)
}
for _ in 0..10{

}

while 循環(huán)

var c = 10
while c > 11  {
// 自增自減?????
    print("大于0")
}

dowhile

repeat {
    statements
} while condition

字符串

  • String 是一個結(jié)構(gòu)體,性能更高
  • String支持直接遍歷
  • swift提供了String 和 NSString之間的無縫轉(zhuǎn)換
let age = 28
let info = "my name is \(name),my age is \(age)"
// 拼接字符串時的格式化
let min = 2
let sec = 3
let timestring  = String.init(format: "%02d:%02d", arguments:[min,sec])
let substr = (timestring as NSString).substring(to: 3)

數(shù)組

  • 創(chuàng)建一個空數(shù)組 var someInts = Int
  • 創(chuàng)建一個帶有默認值的數(shù)組
var threeDoubles = Array(repeating: 0.0, count: 3)
// threeDoubles 是一種 [Double] 數(shù)組,等價于 [0.0, 0.0, 0.0]
  • 通過兩個數(shù)組相加創(chuàng)建一個數(shù)組 +
  • 使用布爾屬性isEmpty作為一個縮寫形式去檢查count屬性是否為0:
  • 也可以使用append(_:)方法在數(shù)組后面添加新的數(shù)據(jù)項
  • 如果我們同時需要每個數(shù)據(jù)項的值和索引值,可以使用enumerated()方法來進行數(shù)組遍歷。enumerated()返回一個由每一個數(shù)據(jù)項索引值和數(shù)據(jù)值組成的元組。我們可以把這個元組分解成臨時常量或者變量來進行遍歷:
for (index, value) in shoppingList. enumerated() {
    print("Item \(String(index + 1)): \(value)")
}

集合

  • 集合(Set)用來存儲相同類型并且沒有確定順序的值。當集合元素順序不重要時或者希望確保每個元素只出現(xiàn)一次時可以使用集合而不是數(shù)組
  • var favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"]
    // favoriteGenres 被構(gòu)造成含有三個初始值的集合
  • Swift 的Set類型沒有確定的順序,為了按照特定順序來遍歷一個Set中的值可以使用sorted()方法,它將返回一個有序數(shù)組,這個數(shù)組的元素排列順序由操作符'<'對元素進行比較的結(jié)果來確定.
  • 集合運算
  • 使用intersection(_:)方法根據(jù)兩個集合中都包含的值創(chuàng)建的一個新的集合。
  • 使用symmetricDifference(_:)方法根據(jù)在一個集合中但不在兩個集合中的值創(chuàng)建一個新的集合。
  • 使用union(_:)方法根據(jù)兩個集合的值創(chuàng)建一個新的集合。
  • 使用subtracting(_:)方法根據(jù)不在該集合中的值創(chuàng)建一個新的集合。
let oddDigits: Set = [1, 3, 5, 7, 9]
let evenDigits: Set = [0, 2, 4, 6, 8]
let singleDigitPrimeNumbers: Set = [2, 3, 5, 7]

oddDigits.union(evenDigits).sorted()
// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
oddDigits. intersection(evenDigits).sorted()
// []
oddDigits.subtracting(singleDigitPrimeNumbers).sorted()
// [1, 9]
oddDigits. symmetricDifference(singleDigitPrimeNumbers).sorted()
// [1, 2, 9]


let houseAnimals: Set = ["??", "??"]
let farmAnimals: Set = ["??", "??", "??", "??", "??"]
let cityAnimals: Set = ["??", "??"]

houseAnimals.isSubset(of: farmAnimals)
// true
farmAnimals.isSuperset(of: houseAnimals)
// true
farmAnimals.isDisjoint(with: cityAnimals)
// true

字典

  • 創(chuàng)建字典
var dict = [String : AnyObject]()
  • 和數(shù)組一樣,我們可以通過字典的只讀屬性count來獲取某個字典的數(shù)據(jù)項數(shù)量
  • 使用布爾屬性isEmpty作為一個縮寫形式去檢查count屬性是否為0
  • ,字典的updateValue(_:forKey:)方法可以設(shè)置或者更新特定鍵對應(yīng)的值
  • 如果我們只是需要使用某個字典的鍵集合或者值集合來作為某個接受Array實例的 API 的參數(shù),可以直接使用keys或者values屬性構(gòu)造一個新數(shù)組
let airportCodes = [String](airports.keys)
// airportCodes 是 ["YYZ", "LHR"]

let airportNames = [String](airports.values)
// airportNames 是 ["Toronto Pearson", "London Heathrow"]
  • 遍歷字典 forin keys values
  • 遍歷所有鍵值
for (key , value) in dictm{

}
  • 合并字典:即使類型一致也不能相加合并

元組

*元組的基本寫法

let info = ("lili",18,1.88)
info.0
info.1
  • 給元組的每個元素起一個別名
let info = (name :"lili",age : 18,height : 1.88)
info.name
info.age
  • 元組中元素的別名,就是元組的名稱
    let (name,age,height) = ("lili",18,1.88)

forin

  • 使用 stride(from:to:by:) 函數(shù)跳過不需要的標記。
let minuteInterval = 5
for tickMark in stride(from: 0, to: minutes, by: minuteInterval) {
    // 每5分鐘呈現(xiàn)一個刻度線 (0, 5, 10, 15 ... 45, 50, 55)
}
可以在閉區(qū)間使用 stride(from:through:by:) 起到同樣作用:
let hours = 12
let hourInterval = 3
for tickMark in stride(from: 3, through: hours, by: hourInterval) {
    // 每3小時呈現(xiàn)一個刻度線 (3, 6, 9, 12)
}

可選類型

定義可選類型

  • 方法一 不常用
* var name : Optional<String> = nil
* var name : String? = nil
  • 如果你聲明一個可選常量或者變量但是沒有賦值,它們會自動被設(shè)置為 nil
var surveyAnswer: String?
// surveyAnswer 被自動設(shè)置為 nil
  • Swift 的 nil 和 Objective-C 中的 nil 并不一樣。在 Objective-C 中,nil 是一個指向不存在對象的指針。在 Swift 中,nil 不是指針——它是一個確定的值,用來表示值缺失。任何類型的可選狀態(tài)都可以被設(shè)置為 nil,不只是對象類型。
  • 注意:強制解包是非常危險的,如果可選類型為nil,強制解包系統(tǒng)會崩潰
    建議:在前置解包前,先對可選類型進行判斷,判斷是否nil
if name != nil {
print(name!)
}```

* 可選綁定
  * 判斷name是否有值,如果沒有值,直接不執(zhí)行{}
  * 如果name有值,系統(tǒng)會自動將name進行強制解包,并且將解包后的結(jié)果賦值給name

if let name = name {
print(name)
}

* 你可以在可選綁定中使用常量和變量。如果你想在if語句的第一個分支中操作 actualNumber 的值,你可以改成 if var actualNumber,這樣可選類型包含的值就會被賦給一個變量而非常量。
### 隱式解析可選類型

let possibleString: String? = "An optional string."
let forcedString: String = possibleString! // 需要感嘆號來獲取值

let assumedString: String! = "An implicitly unwrapped optional string."
let implicitString: String = assumedString // 不需要感嘆號


### 錯誤處理
* 當一個函數(shù)遇到錯誤條件,它能報錯。調(diào)用函數(shù)的地方能拋出錯誤消息并合理處理。

func makeASandwich() throws {
// ...
}

do {
try makeASandwich()
eatASandwich()
} catch SandwichError.outOfCleanDishes {
washDishes()
} catch SandwichError.missingIngredients(let ingredients) {
buyGroceries(ingredients)
}

NO

### 字符串
* 判斷是否為""

if emptyString.isEmpty {
print("Nothing to see here")
}


* 字符串插值:您插入的字符串字面量的每一項都在以反斜線為前綴的圓括號中:

let multiplier = 3
let message = "(multiplier) times 2.5 is (Double(multiplier) * 2.5)"
// message 是 "3 times 2.5 is 7.5"

* 如果想要獲得一個字符串中Character值的數(shù)量,可以使用字符串的characters屬性的count屬性:
* 

greeting[greeting.endIndex] // error
greeting.index(after: endIndex) // error

## Array

let oddNumbers = [1,3,5,7]

* 創(chuàng)建空數(shù)組
 * var emptyDoubles : [Double] = []
 * The full type name is also allowed
  var emptyFloats: Array<Float> = Array()

* 如果你需要一個使用默認值提前初始化的數(shù)組

let digitCounts = Array(repeatElement(0, count: 10))

### 比較運算符
* 注意: Swift 也提供恒等(===
)和不恒等(!==
)這兩個比較符來判斷兩個對象是否引用同一個對象實例。
### 空合運算符
* a ?? b  表述的意思:a != nil ? a! : b

###元組比較
* Swift 標準庫只能比較七個以內(nèi)元素的元組比較函數(shù)。如果你的元組元素超過七個時,你需要自己實現(xiàn)比較運算符。
* 因為 Int 和 String 類型的值可以比較,所以類型為 (Int, String) 的元組也可以被比較。

### 區(qū)間運算符
* 閉區(qū)間運算符: 閉區(qū)間運算符(a...b)定義一個包含從 a 到 b(包括 a 和 b)的所有值的區(qū)間。a 的值不能超過 b
* 半開區(qū)間運算符:半開區(qū)間運算符(a..<b)定義一個從 a 到 b 但不包括 b 的區(qū)間。 之所以稱為半開區(qū)間,是因為該區(qū)間包含第一個值而不包括最后的值。
### 邏輯組合運算符
* Swift 邏輯操作符 && 和 || 是左結(jié)合的,這意味著擁有多元邏輯操作符的復(fù)合表達式優(yōu)先計算最左邊的子表達式。
* 數(shù)組遍歷

let streets = ["mahadun","newyork"]
for street in streets {
print("I don't live on \(street).")
}

* 判斷數(shù)組是否為空 isEmpty

if oddNumbers.isEmpty {
print("數(shù)組為空")
}else{
print("i know(oddNumbers.count) odd Numbers")

}

*  取到數(shù)組的第一個 最后一個元素 ,如果數(shù)組為空,返回nil

if let firstElement = oddNumbers.first , let lastelement = oddNumbers.last {
print(firstElement, lastelement, separator: ", ")
}

* 利用角標訪問數(shù)組元素,不在 0..<count 會報數(shù)組越界錯誤

* 增加或者刪除數(shù)組元素

var students = ["ben","ivy","jodell"]
// 添加單個元素 append(_:) 一次添加多個元素 append(contentsOf:)
students.append("maxi")
students.append(contentsOf: ["shaki","william"])
// 插入一個或多個元素
students.insert("liam", at: 3)
// 刪除元素
students.remove(at: 0)
// 刪除最后一個
students.removeLast()

* 修改元素
students[0] = "dddd"

**當數(shù)組元素的個數(shù)超過初始容量,數(shù)組會將分配更大的內(nèi)存區(qū)域并將其元素復(fù)制到新存儲中。新存儲空間是舊存儲容量的倍數(shù)**

*  修改數(shù)組的副本copy
   * 如果數(shù)據(jù)類型為int 結(jié)構(gòu)體類型,修改原數(shù)組內(nèi)容不會影響副本的內(nèi)容

var numbers = [1, 2, 3, 4, 5]
var numbersCopy = numbers
numbers[0] = 100
print(numbers)
// Prints "[100, 2, 3, 4, 5]"
print(numbersCopy)
// Prints "[1, 2, 3, 4, 5]"


 * 如果數(shù)組元素是對象

class InergerReference{
var value = 10
}
var firstIntegers = [InergerReference(),InergerReference()]
var secondInergers = firstIntegers
firstIntegers[0].value = 100
print(firstIntegers[0].value,secondInergers[0].value)
// 100 100
firstIntegers[0] = InergerReference()
print(firstIntegers[0].value,secondInergers[0].value)
// 10 100

*  Array 與 NSArray的轉(zhuǎn)換 用as


## Dictionary
*  如何創(chuàng)建一個空字典
 var emptyDict: [String : String] = [:]
* 通過key來取值 取出來的值我可選項
 print(dictionary[200] ?? "")

if let message = dictionary[500]{
print(message)
}else{
print("meiyou改制")
}```

  • 添加/修改鍵值對
    dictionary[100] = "text"
  • 對已經(jīng)存在的鍵賦值nil,改鍵值對會被移除
var interstingNumbers = ["primes" : [2,3,5,5,11,13],
                         "trianguler" : [1,3,4,56,6]]
for key in interstingNumbers.keys {
    interstingNumbers[key]?.sort(by: >)
}
print(interstingNumbers["primes"] ?? "")
  • 遍歷字典 每個字典都是無序的鍵值對的集合
var imagePaths = ["star": "/glyphs/star.png",
                  "portrait": "/images/content/portrait.jpg",
                  "spacer": "/images/shared/spacer.gif"]

for (key,value) in imagePaths {
    print("\(key) : \(value)")
}
  • 創(chuàng)建字典
var dict : [String : String] = Dictionary.init(minimumCapacity: 10)
dict["name"] = "lili"
dict.isEmpty
dict.count
  • 訪問字典的鍵值對
imagePaths["star"]
imagePaths.index(forKey: "spacer")
imagePaths.first
imagePaths.keys
imagePaths.values
  • 添加鍵值對
imagePaths.updateValue("falsh.png", forKey: "xxx")
imagePaths
  • 移除鍵值對
imagePaths.removeValue(forKey: "flash")
imagePaths.removeAll()
  • 遍歷字典
imagePaths.enumerated()
imagePaths.makeIterator()
imagePaths.underestimatedCount
imagePaths.first

可選項 Optional

  • 可選項 ?
let shortForm: Int? = Int("33")
// 可選項包含兩個分支 Optional.some
let number: Int? = Optional.some(44)
let nonumber: Int? = Optional.none
print(nonumber == nil)
  • 在很多情況下使用可選項都必須進行解包
let imagePaths = ["star": "/glyphs/star.png",
                  "portrait": "/images/content/portrait.jpg",
                  "spacer": "/images/shared/spacer.gif"]``` 
 * 解包方式一: if let 

if let starPath = imagePaths["star"] {
print("The star image is at '(starPath)'")
} else {
print("Couldn't find the star image")
}```

  • ?? 當為nil時提供一個默認值
let defaultiamgepath = "/iamges/default.png"
let heartpath = imagePaths["heart"] ?? defaultiamgepath
  • ?? 可以多個一起使用
let shapePath = imagePaths["cir"] ?? imagePaths["squ"] ?? defaultiamgepath
  • 強制解包 解包失敗會崩潰
let num = Int("42")!
let isPng = imagePaths["star"]! .hasSuffix(".png")

switch 語句

  • 不存在隱式的貫穿,不需要在 case 分支中顯式地使用break語句。
  • 每一個 case 分支都必須包含至少一條語句。像下面這樣書寫代碼是無效的,因為第一個 case 分支是空的
let anotherCharacter: Character = "a"
switch anotherCharacter {
case "a": // 無效,這個分支下面沒有語句
case "A":
    print("The letter A")
default:
    print("Not the letter A")
}
// 這段代碼會報編譯錯誤
let anotherCharacter: Character = "a"
switch anotherCharacter {
case "a", "A":
    print("The letter A")
default:
    print("Not the letter A")
}
// 輸出 "The letter A
  • 區(qū)間匹配 case 分支的模式也可以是一個值的區(qū)間。
let approximateCount = 62
let countedThings = "moons orbiting Saturn"
var naturalCount: String
switch approximateCount {
case 0:
    naturalCount = "no"
case 1..<5:
    naturalCount = "a few"
case 5..<12:
    naturalCount = "several"
case 12..<100:
    naturalCount = "dozens of"
case 100..<1000:
    naturalCount = "hundreds of"
default:
    naturalCount = "many"
}
print("There are \(naturalCount) \(countedThings).")
// 輸出 "There are dozens of moons orbiting Saturn."
  • case 分支的模式可以使用where語句來判斷額外的條件
let yetAnotherPoint = (1, -1)
switch yetAnotherPoint {
case let (x, y) where x == y:
    print("(\(x), \(y)) is on the line x == y")
case let (x, y) where x == -y:
    print("(\(x), \(y)) is on the line x == -y")
case let (x, y):
    print("(\(x), \(y)) is just some arbitrary point")
}
// 輸出 "(1, -1) is on the line x == -y"
  • 復(fù)合匹配 當多個條件可以使用同一種方法來處理時,可以將這幾種可能放在同一個case后面,并且用逗號隔開。當case后面的任意一種模式匹配的時候,這條分支就會被匹配。并且,如果匹配列表過長,還可以分行書寫
let someCharacter: Character = "e"
switch someCharacter {
case "a", "e", "i", "o", "u":
    print("\(someCharacter) is a vowel")
case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m",
     "n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z":
    print("\(someCharacter) is a consonant")
default:
    print("\(someCharacter) is not a vowel or a consonant")
}
// 輸出 "e is a vowel"

控制轉(zhuǎn)移語句

  • continue continue語句告訴一個循環(huán)體立刻停止本次循環(huán),重新開始下次循環(huán)
  • break語句會立刻結(jié)束整個控制流的執(zhí)行。當你想要更早的結(jié)束一個switch代碼塊或者一個循環(huán)體時,你都可以使用break語句

*Switch 語句中的 break
當在一個switch代碼塊中使用break時,會立即中斷該switch代碼塊的執(zhí)行,并且跳轉(zhuǎn)到表示switch代碼塊結(jié)束的大括號(})后的第一行代碼

  • 貫穿
let integerToDescribe = 5
var description = "The number \(integerToDescribe) is"
switch integerToDescribe {
case 2, 3, 5, 7, 11, 13, 17, 19:
    description += " a prime number, and also"
    fallthrough
default:
    description += " an integer."
}
print(description)
// 輸出 "The number 5 is a prime number, and also an integer."

提前退出

  • 像if語句一樣,guard的執(zhí)行取決于一個表達式的布爾值。我們可以使用guard語句來要求條件必須為真時,以執(zhí)行g(shù)uard語句后的代碼。不同于if語句,一個guard語句總是有一個else從句,如果條件不為真則執(zhí)行else從句中的代碼
func greet(person: [String: String]) {
    guard let name = person["name"] else {
        return
    }
    print("Hello \(name)")
    guard let location = person["location"] else {
        print("I hope the weather is nice near you.")
        return
    }
    print("I hope the weather is nice in \(location).")
}

檢測API的可用性 最后一個參數(shù),*,是必須的,用于指定在所有其它平臺中,如果版本號高于你的設(shè)備指定的最低版本,if語句的代碼塊將會運行

if #available(iOS 10, macOS 10.12, *) {
    // 在 iOS 使用 iOS 10 的 API, 在 macOS 使用 macOS 10.12 的 API
} else {
    // 使用先前版本的 iOS 和 macOS 的 API
}

函數(shù)

  • 多個相同類型參數(shù) (可變參數(shù)一個函數(shù)最多只能擁有一個可變參數(shù)。)
func sumof(numbers:Int...) ->Int{
    var sum = 0
    for num in numbers {
        sum += num
    }
    return sum
}
sumof(numbers: 1,2,3,5)```
* swift中的默認參數(shù)

func makeCoffee(coffeename: String = "藍山"){
print("我要喝(coffeename)咖啡")
}
makeCoffee()
makeCoffee(coffeename: "貓屎")

* 有參有返回值

func greet(name: String,day: String,number: Int) -> String{

return "Hello \(name),Today is\(day),\(number)"

}
print(greet(name: "zhangsan", day: "33", number: 23))


* 函數(shù)返回值為元組

可選元組類型如 (Int, Int)? 與元組包含可選類型如 (Int?, Int?) 是不同的.可選的元組類型,整個元組是可選的,而不只是元組中的每個元素值。
func calculate(scores: [Int]) -> (max: Int,min: Int,sum: Int){
var max = scores[0]
var min = scores[0]
var sum = 0

for num in scores {
    if num > max {
        max = num
    }else if num < min{
        min = num
    }
    sum += num
}
return (max,min,sum)

}
let statistics = calculate(scores: [3,4,5])
print(statistics.max)
print(statistics.0)

* 輸入輸出函數(shù)

func swapTwoInts(_ a: inout Int, _ b: inout Int) {
let temporaryA = a
a = b
b = temporaryA
}

var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
print("someInt is now (someInt), and anotherInt is now (anotherInt)")
// 打印 "someInt is now 107, and anotherInt is now 3"


* 函數(shù)作為返回類型

func makeIncrementer() -> ((Int,Int) -> Int){

func addNumber(num1: Int,num2: Int) -> Int{
    return num1 + num2
}
return addNumber

}

let add = makeIncrementer()
add(3,4)

* **函數(shù)作為參數(shù)(重點)**
 * 平方

func square(a: Float) -> Float{

return a * a

}
square(a: 2.0)```

  • 立方
func cube(a: Float) -> Float{
    
    return a * a * a
}
cube(a: 2.0)```
 * 平均值

func averageSumm(num1: Float,num2: Float,function:(Float -> Float)) -> Float{

return (function(num1) + function(num2))/2

}```

  • 函數(shù)的嵌套使用
func test(){

    func demo(){}
    demo()
}
test()
  • 排序
var numbers = [1,3,2,5,63,7,0]
let sortNmbers = numbers.sorted(){
    
     $0 < $1
}
print(sortNmbers)

class Strudent : NSObject{
    // 定義存儲屬性
    var name: String?
    var age: Int = 0
    var mathScore: Double = 0
    var chineseScore: Double = 0
    
    // 定義計算型屬性:通過別的方式計算得到結(jié)果的屬性
    var averageScore: Double{
    // 在swift中如果使用當前對象的屬性和方法不需要添加self
    return (mathScore + chineseScore) * 0.5
    }
    // 定義類屬性: 類屬性是和整個類相關(guān)的屬性,而且是通過類名來進行訪問
    static var courseCount: Int = 0
    
}
// 給類屬性賦值
Strudent.courseCount = 2
let stu = Strudent()
//stu.age = 20
stu.name = "zhangsan"
stu.mathScore = 50
stu.chineseScore = 60
stu.averageScore
// 解包
if let name = stu.name {
    print(name)
}
// 可以利用KVC賦值
stu.setValue("lisi", forKey: "name")
  • 監(jiān)聽屬性變化
class Person: NSObject{

//    var name: String?
    var name: String?{
        // 監(jiān)聽屬性的變化
        willSet {// 屬性即將改變時進行監(jiān)聽
        print("willsetlllll")
        }
        didSet {//屬性已經(jīng)改變時進行監(jiān)聽
        print("didsettttt")
        }
    
    }
    
    
    // 在構(gòu)造函數(shù)中,如果沒有明確super.init(),那么系統(tǒng)會幫助調(diào)用super.init()
    override init() {
        super.init()
        print("=====")
    }
    
    // 自定義構(gòu)造函數(shù)
    init(name: String) {
        self.name = name
    }
    
    // 字典轉(zhuǎn)模型
    init(dict: [String: AnyObject]) {
        super.init()
        setValuesForKeys(dict)
    }
    override func setValue(_ value: Any?, forUndefinedKey key: String) {
        
    }
}

//let p1 = Person.init()
//let p2 = Person.init(name: "lisi")
let p3 = Person.init(dict: ["name": "wangwu" as AnyObject,
                            "age": 24 as AnyObject
                            ])
print(p3.name ?? "")

便利構(gòu)造函數(shù)

 1.遍歷構(gòu)造函數(shù)通常都是寫在extension里面
 2.遍歷構(gòu)造函數(shù)init前面需要加載convenience
 3.在遍歷構(gòu)造函數(shù)中需要明確的調(diào)用self.init()
extension UIButton {

    convenience init(imageName: String,backGroundName: String) {
        self.init()
        setImage(UIImage.init(named:imageName), for:UIControlState())
        setImage(UIImage.init(named: imageName + "_highlighted"), for: .highlighted)
        setBackgroundImage(UIImage.init(named: backGroundName), for: .normal)
        setBackgroundImage(UIImage.init(named: backGroundName + "highlighted"), for: .highlighted)
        sizeToFit()
    }
}

重寫一個類的description屬性

    // MARK:- 重寫description
    override var description: String{
    return dictionaryWithValues(forKeys: ["access_token", "expires_in", "uid"]).description
    }

點擊事件需要添加@objc fileprivate 非對外方法添加fileprivate

GCD 的使用

  • 調(diào)度組:
        let group = DispatchGroup.init()
        // 入組
        group.enter()
        // 出租
        group.leave()
        // 通知
        group.notify(queue: DispatchQueue.main) { 
            // 執(zhí)行code
        }
  • 延遲執(zhí)行
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 5) { 
            // 執(zhí)行code
        }

        let queue = DispatchQueue.init(label: "")
        queue.async { 
            <#code#>
        }

隊列相關(guān)

// 創(chuàng)建隊列
let queue = DispatchQueue(label: "com.appcoda.myqueue")
// 指定優(yōu)先級
 let queue1 = DispatchQueue.init(label: "com.appcoda.myqueue1", qos:.background)

 // 創(chuàng)建一個并發(fā)隊列
 let queue1 = DispatchQueue.init(label: "com.appcoda.myqueue1",attributes:.concurrent)

 //并發(fā)執(zhí)行
queue1.async {
            for i in 100 ..< 110{
                print("??",i)
            }
        }
// 獲取全局隊列
DispatchQueue.global()
// 主隊列
DispatchQueue.main

workitem


  // workitem
    func useWorkItem() {
        var value = 10
        
        // 方法1
        let workItem = DispatchWorkItem {
            value += 5
        }
        workItem.perform()
        
        // 方法2
        let queue = DispatchQueue.global(qos: .utility)
        
        queue.async(execute: workItem)
        
        //通知
        workItem.notify(queue: DispatchQueue.main)        {
            print("value = ", value)
        }
    }

閉包

  • 閉包可以捕獲和存儲其所在上下文中任意常量和變量的引用。被稱為包裹常量和變量。 Swift 會為你管理在捕獲過程中涉及到的所有內(nèi)存操作。
{ (parameters) -> returnType in
    statements
}

枚舉

  • 應(yīng)該以一個大寫字母開頭。給枚舉類型起一個單數(shù)名字而不是復(fù)數(shù)名字
與 C 和 Objective-C 不同,Swift 的枚舉成員在被創(chuàng)建時不會被賦予一個默認的整型值。在上面的CompassPoint例子中,north,south,east和west不會被隱式地賦值為0,1,2和3。相反,這些枚舉成員本身就是完備的值,這些值的類型是已經(jīng)明確定義好的CompassPoint類型。
enum CompassPoint {
    case north
    case south
    case east
    case west
}
  • 多個成員值可以出現(xiàn)在同一行上,用逗號隔開:
enum Planet {
    case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune
}
  • 使用switch語句匹配枚舉值
directionToHead = .south
switch directionToHead {
    case .north:
        print("Lots of planets have a north")
    case .south:
        print("Watch out for penguins")
    case .east:
        print("Where the sun rises")
    case .west:
        print("Where the skies are blue")
}
// 打印 "Watch out for penguins”

判斷一個枚舉類型的值時,switch語句必須窮舉所有情況。如果忽略了.west這種情況,上面那段代碼將無法通過編譯,因為它沒有考慮到CompassPoint的全部成員。強制窮舉確保了枚舉成員不會被意外遺漏。

  • 當不需要匹配每個枚舉成員的時候,你可以提供一個default分支來涵蓋所有未明確處理的枚舉成員
let somePlanet = Planet.earth
switch somePlanet {
case .earth:
    print("Mostly harmless")
default:
    print("Not a safe place for humans")
}
// 打印 "Mostly harmless”
  • 原始值的隱式賦值
  • 在使用原始值為整數(shù)或者字符串類型的枚舉時,不需要顯式地為每一個枚舉成員設(shè)置原始值,Swift 將會自動為你賦值。
    例如,當使用整數(shù)作為原始值時,隱式賦值的值依次遞增1。如果第一個枚舉成員沒有設(shè)置原始值,其原始值將為0
  • 當使用字符串作為枚舉類型的原始值時,每個枚舉成員的隱式原始值為該枚舉成員的名稱。
  • 使用枚舉成員的rawValue屬性可以訪問該枚舉成員的原始值:
let earthsOrder = Planet.earth.rawValue
// earthsOrder 值為 3

let sunsetDirection = CompassPoint.west.rawValue
// sunsetDirection 值為 "west"
  • 遞歸枚舉
indirect enum ArithmeticExpression {
    case number(Int)
    case addition(ArithmeticExpression, ArithmeticExpression)
    case multiplication(ArithmeticExpression, ArithmeticExpression)
}

類和結(jié)構(gòu)體

  • 結(jié)構(gòu)體總是通過被復(fù)制的方式在代碼中傳遞,不使用引用計數(shù)。
class SomeClass {
    // 在這里定義類
}
struct SomeStructure {
    // 在這里定義結(jié)構(gòu)體
}
  • 構(gòu)造器最簡單形式是在結(jié)構(gòu)體或者類型名稱后跟隨一對空括號
  • 與 Objective-C 語言不同的是,Swift 允許直接設(shè)置結(jié)構(gòu)體屬性的子屬性。上面的最后一個例子,就是直接設(shè)置了someVideoMode中resolution屬性的width這個子屬性,以上操作并不需要重新為整個resolution屬性設(shè)置新值。
  • 結(jié)構(gòu)體類型的成員逐一構(gòu)造器所有結(jié)構(gòu)體都有一個自動生成的成員逐一構(gòu)造器,用于初始化新結(jié)構(gòu)體實例中成員的屬性。新實例中各個屬性的初始值可以通過屬性的名稱傳遞到成員逐一構(gòu)造器之中
let vga = Resolution(width:640, height: 480)
  • 結(jié)構(gòu)體和枚舉是值類型
    值類型被賦予給一個變量、常量或者被傳遞給一個函數(shù)的時候,其值會被拷貝。
  • 恒等運算符
    • 因為類是引用類型,有可能有多個常量和變量在幕后同時引用同一個類實例。(對于結(jié)構(gòu)體和枚舉來說,這并不成立。因為它們作為值類型,在被賦予到常量、變量或者傳遞到函數(shù)時,其值總是會被拷貝。)
    • 等價于(===)
      不等價于(!==)
  • 字符串、數(shù)組、和字典類型的賦值與復(fù)制行為
    • Swift 中,許多基本類型,諸如String,Array和Dictionary類型均以結(jié)構(gòu)體的形式實現(xiàn)。這意味著被賦值給新的常量或變量,或者被傳入函數(shù)或方法中時,它們的值會被拷貝。Objective-C 中NSString,NSArray和NSDictionary類型均以類的形式實現(xiàn),而并非結(jié)構(gòu)體。它們在被賦值或者被傳入函數(shù)或方法時,不會發(fā)生值拷貝,而是傳遞現(xiàn)有實例的引用。

屬性

  • 存儲屬性只能用于類和結(jié)構(gòu)體,計算屬性可以用于類結(jié)構(gòu)體和枚舉.
  • 如果創(chuàng)建了一個結(jié)構(gòu)體的實例并將其賦值給一個常量,則無法修改該實例的任何屬性,即使有屬性被聲明為變量也不行:
let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)
// 該區(qū)間表示整數(shù)0,1,2,3
rangeOfFourItems.firstValue = 6
// 盡管 firstValue 是個變量屬性,這里還是會報錯

這種行為是由于結(jié)構(gòu)體(struct)屬于值類型。當值類型的實例被聲明為常量的時候,它的所有屬性也就成了常量。

屬于引用類型的類(class)則不一樣。把一個引用類型的實例賦給一個常量后,仍然可以修改該實例的變量屬性

  • 懶加載屬性lazy

必須將延遲存儲屬性聲明成變量(使用 var 關(guān)鍵字),因為屬性的初始值可能在實例構(gòu)造完成之后才會得到。而常量屬性在構(gòu)造過程完成之前必須要有初始值,因此無法聲明成延遲屬性。注意
如果一個被標記為 lazy 的屬性在沒有初始化時就同時被多個線程訪問,則無法保證該屬性只會被初始化一次。

  • 計算型屬性:
struct AlternativeRect {
    var origin = Point()
    var size = Size()
    var center: Point {
        get {
            let centerX = origin.x + (size.width / 2)
            let centerY = origin.y + (size.height / 2)
            return Point(x: centerX, y: centerY)
        }
        set {
            origin.x = newValue.x - (size.width / 2)
            origin.y = newValue.y - (size.height / 2)
        }
    }
}
  • 只讀計算屬性只有 getter 沒有 setter 的計算屬性就是只讀計算屬性。只讀計算屬性總是返回一個值,可以通過點運算符訪問,但不能設(shè)置新的值

注意
必須使用 var 關(guān)鍵字定義計算屬性,包括只讀計算屬性,因為它們的值不是固定的。let 關(guān)鍵字只用來聲明常量屬性,表示初始化后再也無法修改的值

  • 只讀計算屬性的聲明可以去掉 get 關(guān)鍵字和花括號:
struct Cuboid {
    var width = 0.0, height = 0.0, depth = 0.0
    var volume: Double {
        return width * height * depth
    }
}
let fourByFiveByTwo = Cuboid(width: 4.0, height: 5.0, depth: 2.0)
print("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")
// 打印 "the volume of fourByFiveByTwo is 40.0"
  • 屬性觀察器
class StepCounter {
    var totalSteps: Int = 0 {
        willSet(newTotalSteps) {
            print("About to set totalSteps to \(newTotalSteps)")
        }
        didSet {
            if totalSteps > oldValue  {
                print("Added \(totalSteps - oldValue) steps")
            }
        }
    }
}
let stepCounter = StepCounter()
stepCounter.totalSteps = 200
// About to set totalSteps to 200
// Added 200 steps
stepCounter.totalSteps = 360
// About to set totalSteps to 360
// Added 160 steps
stepCounter.totalSteps = 896
// About to set totalSteps to 896
// Added 536 steps

全局變量和局部變量

  • 全局變量是在函數(shù)、方法、閉包或任何類型之外定義的變量。局部變量是在函數(shù)、方法或閉包內(nèi)部定義的變量。

注意全局的常量或變量都是延遲計算的,跟[延遲存儲屬性]相似,不同的地方在于,全局的常量或變量不需要標記lazy
修飾符。局部范圍的常量或變量從不延遲計算。

方法

  • 類、結(jié)構(gòu)體、枚舉都可以定義實例方法;類、結(jié)構(gòu)體、枚舉也可以定義類型方法

結(jié)構(gòu)體和枚舉能夠定義方法是 Swift 與 C/Objective-C 的主要區(qū)別之一。

  • 實際上,你不必在你的代碼里面經(jīng)常寫self。不論何時,只要在一個方法中使用一個已知的屬性或者方法名稱,如果你沒有明確地寫self,Swift 假定你是指當前實例的屬性或者方法。

  • 在實例方法中修改值類型

  • 結(jié)構(gòu)體和枚舉是值類型。默認情況下,值類型的屬性不能在它的實例方法中被修改。

但是,如果你確實需要在某個特定的方法中修改結(jié)構(gòu)體或者枚舉的屬性,你可以為這個方法選擇可變(mutating)行為,然后就可以從其方法內(nèi)部改變它的屬性;并且這個方法做的任何改變都會在方法執(zhí)行結(jié)束時寫回到原始結(jié)構(gòu)中。方法還可以給它隱含的self屬性賦予一個全新的實例,這個新實例在方法結(jié)束時會替換現(xiàn)存實例。

要使用可變方法,將關(guān)鍵字mutating 放到方法的func關(guān)鍵字之前就可以了

struct Point {
    var x = 0.0, y = 0.0
    mutating func moveByX(deltaX: Double, y deltaY: Double) {
        x += deltaX
        y += deltaY
    }
}
var somePoint = Point(x: 1.0, y: 1.0)
somePoint.moveByX(2.0, y: 3.0)
print("The point is now at (\(somePoint.x), \(somePoint.y))")
// 打印 "The point is now at (3.0, 4.0)"

注意,不能在結(jié)構(gòu)體類型的常量(a constant of structure type)上調(diào)用可變方法,因為其屬性不能被改變,即使屬性是變量屬性,

let fixedPoint = Point(x: 3.0, y: 3.0)fixedPoint.moveByX(2.0, y: 3.0)// 這里將會報告一個錯誤
  • 在可變方法中給 self 賦值
    可變方法能夠賦給隱含屬性self一個全新的實例
struct Point {
    var x = 0.0, y = 0.0
    mutating func moveBy(x deltaX: Double, y deltaY: Double) {
        self = Point(x: x + deltaX, y: y + deltaY)
    }
}

類型方法

  • 方法的func關(guān)鍵字之前加上關(guān)鍵字static,來指定類型方法。類還可以用關(guān)鍵字class來允許子類重寫父類的方法實現(xiàn)。

注意
在 Objective-C 中,你只能為 Objective-C 的類類型(classes)定義類型方法(type-level methods)。在 Swift 中,你可以為所有的類、結(jié)構(gòu)體和枚舉定義類型方法。每一個類型方法都被它所支持的類型顯式包含

下標

Swift 的Dictionary類型的下標接受并返回可選類型的值。上例中的numberOfLegs字典通過下標返回的是一個Int?或者說“可選的int”。Dictionary類型之所以如此實現(xiàn)下標,是因為不是每個鍵都有個對應(yīng)的值,同時這也提供了一種通過鍵刪除對應(yīng)值的方式,只需將鍵對應(yīng)的值賦值為nil即可。

繼承

  • 在 Swift 中,繼承是區(qū)分「類」與其它類型的一個基本特征。
  • 可以為類中繼承來的屬性添加屬性觀察器,這樣一來,當屬性值改變時,類就會被通知到??梢詾槿魏螌傩蕴砑訉傩杂^察器,無論它原本被定義為存儲型屬性還是計算型屬性
  • 子類
class SomeClass: SomeSuperclass {
    // 這里是子類的定義
}

重寫

  • 如果要重寫某個特性,你需要在重寫定義的前面加上override關(guān)鍵字。這么做,你就表明了你是想提供一個重寫版本,而非錯誤地提供了一個相同的定義。意外的重寫行為可能會導(dǎo)致不可預(yù)知的錯誤,任何缺少override關(guān)鍵字的重寫都會在編譯時被診斷為錯誤。

在方法someMethod()的重寫實現(xiàn)中,可以通過super.someMethod()來調(diào)用超類版本的someMethod()方法。
在屬性someProperty的 getter 或 setter 的重寫實現(xiàn)中,可以通過super.someProperty來訪問超類版本的someProperty屬性。
在下標的重寫實現(xiàn)中,可以通過super[someIndex]來訪問超類版本中的相同下標。
注意
你不可以為繼承來的常量存儲型屬性或繼承來的只讀計算型屬性添加屬性觀察器。這些屬性的值是不可以被設(shè)置的,所以,為它們提供willSet或didSet實現(xiàn)是不恰當。
此外還要注意,你不可以同時提供重寫的 setter 和重寫的屬性觀察器。如果你想觀察屬性值的變化,并且你已經(jīng)為那個屬性提供了定制的 setter,那么你在 setter 中就可以觀察到任何值變化了。

防止重寫

  • 你可以通過把方法,屬性或下標標記為final來防止它們被重寫,只需要在聲明關(guān)鍵字前加上final修飾符即可(例如:final var,final func,final class func,以及final subscript)。

構(gòu)造過程

  • 構(gòu)造過程是使用類、結(jié)構(gòu)體或枚舉類型的實例之前的準備過程。在新實例可用前必須執(zhí)行這個過程,具體操作包括設(shè)置實例中每個存儲型屬性的初始值和執(zhí)行其他必須的設(shè)置或初始化工作。

  • 類和結(jié)構(gòu)體在創(chuàng)建實例時,必須為所有存儲型屬性設(shè)置合適的初始值。存儲型屬性的值不能處于一個未知的狀態(tài)。

你可以在構(gòu)造器中為存儲型屬性賦初值,也可以在定義屬性時為其設(shè)置默認值。

注意
當你為存儲型屬性設(shè)置默認值或者在構(gòu)造器中為其賦值時,它們的值是被直接設(shè)置的,不會觸發(fā)任何屬性觀察者。

  • 不帶外部名的構(gòu)造器參數(shù)如果你不希望為構(gòu)造器的某個參數(shù)提供外部名字,你可以使用下劃線(_)來顯式描述它的外部名,以此重寫上面所說的默認行為

*構(gòu)造過程中常量屬性的修改 你可以在構(gòu)造過程中的任意時間點給常量屬性指定一個值,只要在構(gòu)造過程結(jié)束時是一個確定的值。一旦常量屬性被賦值,它將永遠不可更改。

注意
對于類的實例來說,它的常量屬性只能在定義它的類的構(gòu)造過程中修改;不能在子類中修改。

  • 默認構(gòu)造器 ()
  • 結(jié)構(gòu)體的逐一成員構(gòu)造器 如果結(jié)構(gòu)體沒有提供自定義的構(gòu)造器,它們將自動獲得一個逐一成員構(gòu)造器,即使結(jié)構(gòu)體的存儲型屬性沒有默認值。
struct Size {
    var width = 0.0, height = 0.0
}
let twoByTwo = Size(width: 2.0, height: 2.0)

類的繼承和構(gòu)造過程

  • 類里面的所有存儲型屬性——包括所有繼承自父類的屬性——都必須在構(gòu)造過程中設(shè)置初始值。
  • 構(gòu)造器的繼承和重寫跟 Objective-C 中的子類不同,Swift 中的子類默認情況下不會繼承父類的構(gòu)造器。Swift 的這種機制可以防止一個父類的簡單構(gòu)造器被一個更精細的子類繼承,并被錯誤地用來創(chuàng)建子類的實例。

注意
子類可以在初始化時修改繼承來的變量屬性,但是不能修改繼承來的常量屬性。

?### 析構(gòu) deinit

  • 在類的定義中,每個類最多只能有一個析構(gòu)器,而且析構(gòu)器不帶任何參數(shù)
deinit {
    // 執(zhí)行析構(gòu)過程
}

擴展

  • 添加計算型屬性和計算型類型屬性
  • 定義實例方法和類型方法
  • 提供新的構(gòu)造器
  • 定義下標
  • 定義和使用新的嵌套類型
  • 使一個已有類型符合某個協(xié)議
extension SomeType {
    // 為 SomeType 添加的新功能寫到這里
}

extension SomeType: SomeProtocol, AnotherProctocol {
    // 協(xié)議實現(xiàn)寫到這里
}

注意
擴展可以添加新的計算型屬性,但是不可以添加存儲型屬性,也不可以為已有屬性添加屬性觀察器。

閉包

  • 閉包表達式語法
{ (parameters) -> returnType in
    statements
}
  • 閉包的函數(shù)體部分由關(guān)鍵字in引入.該關(guān)鍵字表示閉包的參數(shù)和返回值類型定義已經(jīng)完成,閉包函數(shù)體即將開始.
  • 單表達式閉包隱式返回單行表達式閉包可以通過省略 return 關(guān)鍵字來隱式返回單行表達式的結(jié)果
reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )
  • 尾隨閉包
func someFunctionThatTakesAClosure(closure: () -> Void) {
    // 函數(shù)體部分
}

// 以下是不使用尾隨閉包進行函數(shù)調(diào)用
someFunctionThatTakesAClosure(closure: {
    // 閉包主體部分
})

// 以下是使用尾隨閉包進行函數(shù)調(diào)用
someFunctionThatTakesAClosure() {
    // 閉包主體部分
}
  • 值捕獲閉包可以在其被定義的上下文中捕獲常量或變量。即使定義這些常量和變量的原作用域已經(jīng)不存在,閉包仍然可以在閉包函數(shù)體內(nèi)引用和修改這些值。
  • 閉包是引用類型無論你將函數(shù)或閉包賦值給一個常量還是變量,你實際上都是將常量或變量的值設(shè)置為對應(yīng)函數(shù)或閉包的引用
  • 逃逸閉包:當一個閉包作為參數(shù)傳到一個函數(shù)中,但是這個閉包在函數(shù)返回之后才被執(zhí)行,我們稱該閉包從函數(shù)中逃逸。當你定義接受閉包作為參數(shù)的函數(shù)時,你可以在參數(shù)名之前標注 @escaping,用來指明這個閉包是允許“逃逸”出這個函數(shù)的。
  • 逃逸閉包中需要顯式的引用self
  • 在非逃逸閉包中可以隱式的引用self
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容