本篇內容主要講解“什么是Swift語法”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“什么是Swift語法”吧!
Swift 是一門開發 iOS, macOS, watchOS 和 tvOS 應用的新語言。
swift 是一種安全,快速和互動的編程語言。
swift 支持代碼預覽(playgrounds),這個特性可以允許程序員在不編譯和運行應用程序的前提下運行 Swift 代碼并實時查看結果。
Swift 通過采用現代編程模式來避免大量常見編程錯誤:
變量始終在使用前初始化。
檢查數組索引超出范圍的錯誤。
檢查整數是否溢出。
可選值確保明確處理 nil 值。
內存被自動管理。
錯誤處理允許從意外故障控制恢復。
聲明常量和變量, 常量和變量必須在使用前聲明,使用 let 來聲明常量,使用 var 來聲明變量。
示例:
let maximumNumberOfLoginAttempts = 10 var currentLoginAttempt = 0 // 類型注解 var welcomeMessage: String
單行注釋雙正斜杠(//), 多行注釋(/* 多行的 */)。Swift 的多行注釋可以嵌套在其它的多行注釋之中。
示例:
// 這是一個注釋 /* 這也是一個注釋, 但是是多行的 */ /* 這是第一個多行注釋的開頭 /* 這是第二個被嵌套的多行注釋 */ 這是第一個多行注釋的結尾 */
Swift 并不強制要求你在每條語句的結尾處使用分號(;)。
同一行內寫多條獨立的語句必須用分號分隔。
let cat = "????"; print(cat) // 輸出“????”
統一使用 Int 可以提高代碼的可復用性,避免不同類型數字之間的轉換, 并且匹配數字的類型推斷。
示例:
let minValue = UInt8.min // minValue 為 0,是 UInt8 類型let maxValue = UInt8.max // maxValue 為 255,是 UInt8 類型
Swift 是一門類型安全的語言,這意味著 Swift 可以讓你清楚地知道值的類型。
如果你沒有顯式指定類型,Swift 會使用類型推斷來選擇合適的類型。(int、double)。
示例:
let meaningOfLife = 42 // meaningOfLife 會被推測為 Int 類型let pi = 3.14159 // pi 會被推測為 Double 類型
示例:
let decimalInteger = 17let binaryInteger = 0b10001 // 二進制的17let octalInteger = 0o21 // 八進制的17let hexadecimalInteger = 0x11 // 十六進制的17
類型別名(type aliases)就是給現有類型定義另一個名字。你可以使用 typealias 關鍵字來定義類型別名。
示例:
typealias AudioSample = UInt16 var maxAmplitudeFound = AudioSample.min // maxAmplitudeFound 現在是 0
示例:
let orangesAreOrange = truelet turnipsAreDelicious = false
元組(tuples)把多個值組合成一個復合值。元組內的值可以是任意類型,并不要求是相同類型。
示例:
let http404Error = (404, "Not Found") // http404Error 的類型是 (Int, String),值是 (404, "Not Found")
使用可選類型(optionals)來處理值可能缺失的情況??蛇x類型表示兩種可能:或者有值, 你可以解析可選類型訪問這個值, 或者根本沒有值。
示例:
var serverResponseCode: Int? = 404 // serverResponseCode 包含一個可選的 Int 值 404 serverResponseCode = nil // serverResponseCode 現在不包含值
錯誤處理,應對程序執行中可能會遇到的錯誤條件。
示例:
func makeASandwich() throws {
// ...
}do {
try makeASandwich()
eatASandwich()
} catch SandwichError.outOfCleanDishes {
washDishes()
} catch SandwichError.missingIngredients(let ingredients) {
buyGroceries(ingredients)
}斷言和先決條件,是在運行時所做的檢查。
let age = -3 assert(age >= 0, "A person's age cannot be less than zero") // 因為 age < 0,所以斷言會觸發
Swift 支持大部分標準 C 語言的運算符,還提供了 C 語言沒有的區間運算符,例如 a..<b 或 a...b。
運算符分為一元、二元和三元運算符。
閉區間運算符(a...b)定義一個包含從 a 到 b(包括 a 和 b)的所有值的區間。
半開區間運算符(a..<b)定義一個從 a 到 b 但不包括 b 的區間。
閉區間操作符有另一個表達形式,可以表達往一側無限延伸的區間,(a...,...b)。
示例:
let names = ["Anna", "Alex", "Brian", "Jack"]let count = names.countfor i in 0..<count {
print("第 \(i + 1) 個人叫 \(names[i])")
}
// 第 1 個人叫 Anna
// 第 2 個人叫 Alex
// 第 3 個人叫 Brian
// 第 4 個人叫 Jack初始化空字符串,字符串可變性,字符串是值類型,連接字符串和字符(+,+=)。
使用字符,可通過 for-in 循環來遍歷字符串,獲取字符串中每一個字符的值。
字符串插值是一種構建新字符串的方式,可以在其中包含常量、變量、字面量和表達式??梢栽谝延凶址胁迦氤A?、變量、字面量和表達式從而形成更長的字符串。
Swift 提供了三種方式來比較文本值:字符串字符相等、前綴相等和后綴相等。
示例:
// 多行字符串字面量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 singleLineString = "These are the same."let multilineString = """
These are the same.
"""// 字符串插值let multiplier = 3let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"// message 是 "3 times 2.5 is 7.5"// 計算字符數量
var word = "cafe"print("the number of characters in \(word) is \(word.count)")
// 打印輸出“the number of characters in cafe is 4”
var emptyString = "" // 空字符串字面量
var anotherEmptyString = String() // 初始化方法
// 兩個字符串均為空并等價。let catCharacters: [Character] = ["C", "a", "t", "!"]let catString = String(catCharacters)print(catString)
// 打印輸出:“Cat!”Swift 語言提供數組(Array)、集合(Set)和字典(Dictionary)三種基本的集合類型用來存儲集合數據。數組是有序數據的集。集合是無序無重復數據的集。字典是無序的鍵值對的集。
數組使用有序列表存儲同一類型的多個值。相同的值可以多次出現在一個數組的不同位置中。
集合用來存儲相同類型并且沒有確定順序的值。當集合元素順序不重要時或者希望確保每個元素只出現一次時可以使用集合而不是數組。
集合操作,可以高效地完成集合的一些基本操作,比如把兩個集合組合到一起,判斷兩個集合共有元素,或者判斷兩個集合是否全包含,部分包含或者不相交。
字典是一種無序的集合,它存儲的是鍵值對之間的關系,其所有鍵的值需要是相同的類型,所有值的類型也需要相同。每個值(value)都關聯唯一的鍵(key),鍵作為字典中這個值數據的標識符。
示例:
// 集合
var someInts = [Int]()print("someInts is of type [Int] with \(someInts.count) items.")
// 打印“someInts is of type [Int] with 0 items.”
var threeDoubles = Array(repeating: 0.0, count: 3)
// threeDoubles 是一種 [Double] 數組,等價于 [0.0, 0.0, 0.0]
var anotherThreeDoubles = Array(repeating: 2.5, count: 3)
// anotherThreeDoubles 被推斷為 [Double],等價于 [2.5, 2.5, 2.5]
var sixDoubles = threeDoubles + anotherThreeDoubles
// sixDoubles 被推斷為 [Double],等價于 [0.0, 0.0, 0.0, 2.5, 2.5, 2.5]
// enumerated() 方法遍歷數組
var shoppingList: [String] = ["Eggs", "Milk"]for (index, value) in shoppingList.enumerated() {
print("Item \(String(index + 1)): \(value)")
}像 if 語句一樣,guard 的執行取決于一個表達式的布爾值。我們可以使用 guard 語句來要求條件必須為真時,以執行 guard 語句后的代碼。不同于 if 語句,一個 guard 語句總是有一個 else 從句,如果條件不為真則執行 else 從句中的代碼。
Swift 內置支持檢查 API 可用性,編譯器使用 SDK 中的可用信息來驗證我們的代碼中使用的所有 API 在項目指定的部署目標上是否可用。如果我們嘗試使用一個不可用的 API,Swift 會在編譯時報錯。
示例:
let names = ["Anna", "Alex", "Brian", "Jack"]for name in names {
print("Hello, \(name)!")
}let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]for (animalName, legCount) in numberOfLegs {
print("\(animalName)s have \(legCount) legs")
}
// repeat-while 循環的一般格式
repeat {
statements
} while condition
// 提前退出
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).")
}
greet(person: ["name": "John"])
// 輸出“Hello John!”
// 輸出“I hope the weather is nice near you.”
greet(person: ["name": "Jane", "location": "Cupertino"])
// 輸出“Hello Jane!”
// 輸出“I hope the weather is nice in Cupertino.”可選元組返回類型。
定義一個輸入輸出參數時,在參數定義前加 inout 關鍵字。
示例:
// 函數
func greet(person: String) -> String {
let greeting = "Hello, " + person + "!" return greeting
}
func greet(person: String, from hometown: String) -> String {
return "Hello \(person)! Glad you could visit from \(hometown)."}print(greet(person: "Bill", from: "Cupertino"))
// 打印“Hello Bill! Glad you could visit from Cupertino.”
// 可選元組返回類型
func minMax(array: [Int]) -> (min: Int, max: Int)? {
if array.isEmpty { return nil }
var currentMin = array[0]
var currentMax = array[0]
for value in array[1..<array.count] {
if value < currentMin {
currentMin = value
} else if value > currentMax {
currentMax = value
}
}
return (currentMin, currentMax)
}
// 隱式返回的函數
func greeting(for person: String) -> String {
"Hello, " + person + "!"}print(greeting(for: "Dave"))
// 打印 "Hello, Dave!
// 參數標簽
func greet(person: String, from hometown: String) -> String {
return "Hello \(person)! Glad you could visit from \(hometown)."
}
print(greet(person: "Bill", from: "Cupertino"))
// 打印“Hello Bill! Glad you could visit from Cupertino.”閉包是自包含的函數代碼塊,可以在代碼中被傳遞和使用。與一些編程語言中的匿名函數(Lambdas)比較相似。
如果你需要將一個很長的閉包表達式作為最后一個參數傳遞給函數,將這個閉包替換成為尾隨閉包的形式很有用。
閉包可以在其被定義的上下文中捕獲常量或變量。即使定義這些常量和變量的原作用域已經不存在,閉包仍然可以在閉包函數體內引用和修改這些值。
示例:
// 閉包表達式語法
{ (parameters) -> return type in statements
}
// 尾隨閉包let digitNames = [
0: "Zero", 1: "One", 2: "Two", 3: "Three", 4: "Four",
5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"]let numbers = [16, 58, 510]let strings = numbers.map {
(number) -> String in var number = number
var output = "" repeat {
output = digitNames[number % 10]! + output
number /= 10
} while number > 0
return output
}
// strings 常量被推斷為字符串類型數組,即 [String]
// 其值為 ["OneSix", "FiveEight", "FiveOneZero"]
// 值捕獲
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementer() -> Int {
runningTotal += amount
return runningTotal
}
return incrementer
}
// 自動閉包,延遲求值
var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]print(customersInLine.count)
// 打印出“5”let customerProvider = { customersInLine.remove(at: 0) }print(customersInLine.count)
// 打印出“5”print("Now serving \(customerProvider())!")
// Prints "Now serving Chris!"print(customersInLine.count)
// 打印出“4”使用 enum 關鍵詞來創建枚舉并且把它們的整個定義放在一對大括號內。
可以定義 Swift 枚舉來存儲任意類型的關聯值,每個枚舉成員的關聯值類型可以各不相同。
示例:
// 枚舉語法
enum SomeEnumeration {
// 枚舉定義放在這里
}
enum CompassPoint {
case north
case south
case east
case west
}
enum Planet {
case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune
}let somePlanet = Planet.earth
switch somePlanet {case .earth:
print("Mostly harmless")
default:
print("Not a safe place for humans")
}
// 打印“Mostly harmless”
// 關聯值
enum Barcode {
case upc(Int, Int, Int, Int)
case qrCode(String)
}
var productBarcode = Barcode.upc(8, 85909, 51226, 3)
productBarcode = .qrCode("ABCDEFGHIJKLMNOP")
switch productBarcode {case let .upc(numberSystem, manufacturer, product, check):
print("UPC: \(numberSystem), \(manufacturer), \(product), \(check).")case let .qrCode(productCode):
print("QR code: \(productCode).")
}
// 打印“QR code: ABCDEFGHIJKLMNOP.”
// 遞歸枚舉
indirect enum ArithmeticExpression {
case number(Int)
case addition(ArithmeticExpression, ArithmeticExpression)
case multiplication(ArithmeticExpression, ArithmeticExpression)
}let five = ArithmeticExpression.number(5)let four = ArithmeticExpression.number(4)let sum = ArithmeticExpression.addition(five, four)let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))
// (5 + 4) * 2
func evaluate(_ expression: ArithmeticExpression) -> Int {
switch expression {
case let .number(value):
return value
case let .addition(left, right):
return evaluate(left) + evaluate(right)
case let .multiplication(left, right):
return evaluate(left) * evaluate(right)
}
}print(evaluate(product))
// 打印“18”結構體和類作為一種通用而又靈活的結構,成為了人們構建代碼的基礎。你可以使用定義常量、變量和函數的語法,為你的結構體和類定義屬性、添加方法。
示例:
// 類和結構體
struct SomeStructure {
// 在這里定義結構體
}
class SomeClass {
// 在這里定義類
}
struct Resolution {
var width = 0
var height = 0
}
class VideoMode {
var resolution = Resolution()
var interlaced = false var frameRate = 0.0
var name: String?
}屬性將值與特定的類、結構體或枚舉關聯。存儲屬性會將常量和變量存儲為實例的一部分,而計算屬性則是直接計算(而不是存儲)值。計算屬性可以用于類、結構體和枚舉,而存儲屬性只能用于類和結構體。
屬性觀察器監控和響應屬性值的變化,每次屬性被設置值的時候都會調用屬性觀察器,即使新值和當前值相同的時候也不例外。
willSet 在新的值被設置之前調用
didSet 在新的值被設置之后調用
屬性包裝器在管理屬性如何存儲和定義屬性的代碼之間添加了一個分隔層。
類型屬性也是通過點運算符來訪問。但是,類型屬性是通過類型本身來訪問,而不是通過實例。
示例:
// 屬性
struct Point {
var x = 0.0, y = 0.0
}
struct Size {
var width = 0.0, height = 0.0
}
struct Rect {
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(newCenter) {
origin.x = newCenter.x - (size.width / 2)
origin.y = newCenter.y - (size.height / 2)
}
}
}
var square = Rect(origin: Point(x: 0.0, y: 0.0),
size: Size(width: 10.0, height: 10.0))let initialSquareCenter = square.center
square.center = Point(x: 15.0, y: 15.0)print("square.origin is now at (\(square.origin.x), \(square.origin.y))")
// 打印“square.origin is now at (10.0, 10.0)”
// 屬性包裝器
@propertyWrapper
struct TwelveOrLess {
private var number = 0
var wrappedValue: Int {
get { return number }
set { number = min(newValue, 12) }
}
}方法是與某些特定類型相關聯的函數。
類、結構體、枚舉都可以定義實例方法;實例方法為給定類型的實例封裝了具體的任務與功能。
類、結構體、枚舉也可以定義類型方法;類型方法與類型本身相關聯。
示例:
// 方法
class Counter {
var count = 0
func increment() {
count += 1
}
func increment(by amount: Int) {
count += amount
}
func reset() {
count = 0
}
}下標可以定義在類、結構體和枚舉中,是訪問集合、列表或序列中元素的快捷方式
subscript(index: Int) -> Int {
get {
// 返回一個適當的 Int 類型的值
}
set(newValue) {
// 執行適當的賦值操作
}
}
// 示例
struct TimesTable {
let multiplier: Int
subscript(index: Int) -> Int {
return multiplier * index
}
}let threeTimesTable = TimesTable(multiplier: 3)print("six times three is \(threeTimesTable[6])")
// 打印“six times three is 18”
var numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
numberOfLegs["bird"] = 2
// 類型下標
enum Planet: Int {
case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
static subscript(n: Int) -> Planet {
return Planet(rawValue: n)!
}
}let mars = Planet[4]print(mars)不繼承于其它類的類,稱之為基類。
示例:
// 繼承
class SomeClass: SomeSuperclass {
// 這里是子類的定義
}
class Vehicle {
var currentSpeed = 0.0
var description: String {
return "traveling at \(currentSpeed) miles per hour" }
func makeNoise() {
// 什么也不做——因為車輛不一定會有噪音
}
}
class Car: Vehicle {
var gear = 1
override var description: String {
return super.description + " in gear \(gear)" }
}
class AutomaticCar: Car {
override var currentSpeed: Double {
didSet {
gear = Int(currentSpeed / 10.0) + 1
}
}
}構造過程是使用類、結構體或枚舉類型的實例之前的準備過程。
構造器可以通過調用其它構造器來完成實例的部分構造過程。這一過程稱為構造器代理,它能避免多個構造器間的代碼重復。
Swift 為類類型提供了兩種構造器來確保實例中所有存儲型屬性都能獲得初始值,它們被稱為指定構造器和便利構造器。
可以在一個類,結構體或是枚舉類型的定義中,添加一個或多個可失敗構造器。其語法為在 init 關鍵字后面添加問號(init?)。
必要構造器,在類的構造器前添加 required 修飾符表明所有該類的子類都必須實現該構造器。
示例:
// 構造過程init() {
// 在此處執行構造過程
}
struct Fahrenheit {
var temperature: Double
init() {
temperature = 32.0
}
}
var f = Fahrenheit()print("The default temperature is \(f.temperature)° Fahrenheit")
// 打印“The default temperature is 32.0° Fahrenheit”
struct Color {
let red, green, blue: Double
init(red: Double, green: Double, blue: Double) {
self.red = red
self.green = green
self.blue = blue
}
init(white: Double) {
red = white
green = white
blue = white
}
}析構器只適用于類類型,當一個類的實例被釋放之前,析構器會被立即調用。析構器用關鍵字 deinit 來標示,類似于構造器要用 init 來標示。
Swift 會自動釋放不再需要的實例以釋放資源。
示例:
// 析構過程
deinit {
// 執行析構過程
}
class Bank {
static var coinsInBank = 10_000
static func distribute(coins numberOfCoinsRequested: Int) -> Int {
let numberOfCoinsToVend = min(numberOfCoinsRequested, coinsInBank)
coinsInBank -= numberOfCoinsToVend
return numberOfCoinsToVend
}
static func receive(coins: Int) {
coinsInBank += coins
}
}
class Player {
var coinsInPurse: Int
init(coins: Int) {
coinsInPurse = Bank.distribute(coins: coins)
}
func win(coins: Int) {
coinsInPurse += Bank.distribute(coins: coins)
}
deinit {
Bank.receive(coins: coinsInPurse)
}
}可選鏈式調用是一種可以在當前值可能為 nil 的可選值上請求和調用屬性、方法及下標的方法。
通過在想調用的屬性、方法,或下標的可選值后面放一個問號(?),可以定義一個可選鏈。類似在可選值后面放一個嘆號(!)來強制展開它的值。它們的主要區別在于當可選值為空時可選鏈式調用只會調用失敗,然而強制展開將會觸發運行時錯誤。
示例:
class Person {
var residence: Residence?
}
class Residence {
var numberOfRooms = 1
}let john = Person()let roomCount = john.residence!.numberOfRooms
// 這會引發運行時錯誤if let roomCount = john.residence?.numberOfRooms {
print("John's residence has \(roomCount) room(s).")
} else {
print("Unable to retrieve the number of rooms.")
}
// 打印“Unable to retrieve the number of rooms.”
john.residence = Residence()if let roomCount = john.residence?.numberOfRooms {
print("John's residence has \(roomCount) room(s).")
} else {
print("Unable to retrieve the number of rooms.")
}
// 打印“John's residence has 1 room(s).”錯誤處理(Error handling) 是響應錯誤以及從錯誤中恢復的過程。Swift 在運行時提供了拋出、捕獲、傳遞和操作可恢復錯誤(recoverable errors)的一等支持。
在 Swift 中,錯誤用遵循 Error 協議的類型的值來表示。
Swift 中有 4 種處理錯誤的方式??梢园押瘮祾伋龅腻e誤傳遞給調用此函數的代碼(throws)、用 do-catch 語句處理錯誤、將錯誤作為可選類型處理(try?)、或者斷言此錯誤根本不會發生(try!)。
defer 語句將代碼的執行延遲到當前的作用域退出之前。
示例:
// 錯誤處理
enum VendingMachineError: Error {
case invalidSelection //選擇無效
case insufficientFunds(coinsNeeded: Int) //金額不足
case outOfStock //缺貨
}
throw VendingMachineError.insufficientFunds(coinsNeeded: 5)
var vendingMachine = VendingMachine()
vendingMachine.coinsDeposited = 8do {
try buyFavoriteSnack(person: "Alice", vendingMachine: vendingMachine)
print("Success! Yum.")
} catch VendingMachineError.invalidSelection {
print("Invalid Selection.")
} catch VendingMachineError.outOfStock {
print("Out of Stock.")
} catch VendingMachineError.insufficientFunds(let coinsNeeded) {
print("Insufficient funds. Please insert an additional \(coinsNeeded) coins.")
} catch {
print("Unexpected error: \(error).")
}
// 打印“Insufficient funds. Please insert an additional 2 coins.”
// 指定清理操作
func processFile(filename: String) throws {
if exists(filename) {
let file = open(filename)
defer {
close(file)
}
while let line = try file.readline() {
// 處理文件。
}
// close(file) 會在這里被調用,即作用域的最后。
}
}類型轉換在 Swift 中使用 is 和 as 操作符實現。這兩個操作符分別提供了一種簡單達意的方式去檢查值的類型或者轉換它的類型。
可以將類型轉換用在類和子類的層次結構上,檢查特定類實例的類型并且轉換這個類實例的類型成為這個層次結構中的其他類型。
Swift 為不確定類型提供了兩種特殊的類型別名:
Any 可以表示任何類型,包括函數類型。
AnyObject 可以表示任何類類型的實例。
示例:
// 類型轉換
// 一個基類 MediaItem
class MediaItem {
var name: String
init(name: String) {
self.name = name
}
}
class Movie: MediaItem {
var director: String
init(name: String, director: String) {
self.director = director
super.init(name: name)
}
}
class Song: MediaItem {
var artist: String
init(name: String, artist: String) {
self.srtist = artist
super.init(name: name)
}
}let library = [
Movie(name: "Casablanca", director: "Micheal Curtiz"),
Song(name: "Blue Suede Shose", artist: "Elvis Presley"),
Movie(name: "Citizen Kane", director: "Orson Wells"),
Song(name: "The One And Only", artist: "Chesney Hawkes"),
Song(name: "Never Gonna Give You Up", artist: "Rick Astley")
]
var movieCount = 0
var songCount = 0for item in library {
if item is Movie {
movieCount += 1
} else if item is Song {
songCount += 1
}
}print("Media library contains \(movieCount) movies and \(songCount)")
// 打印“Media library contains 2 movies and 3 songs”for item in library {
if let movie = item as? Movie {
print("Movie: \(movie.name), dir. \(movie.director)")
} else if let song = item as? Song {
print("Song: \(song.name), by \(song.artist)")
}
}
// Movie: Casablanca, dir. Michael Curtiz
// Song: Blue Suede Shoes, by Elvis Presley
// Movie: Citizen Kane, dir. Orson Welles
// Song: The One And Only, by Chesney Hawkes
// Song: Never Gonna Give You Up, by Rick AstleySwift 允許定義嵌套類型,可以在支持的類型中定義嵌套的枚舉、類和結構體。
要在一個類型中嵌套另一個類型,將嵌套類型的定義寫在其外部類型的 {} 內,而且可以根據需要定義多級嵌套。
示例:
// 嵌套類型
stuct BlackjackCard {
// 嵌套的 Suit 枚舉
enum Suit: Character {
case spades = "1", hearts = "2", diamonds = "3", clubs = "4" }
// 嵌套的 Rank 枚舉
enum Rank: Int {
case two = 2, three, four, five, six, seven, eight, nine, ten
case jack, queen, king, ace
struct Values {
let first: Int, second: Int?
}
var values: Values {
switch self {
case .ace:
return Values(first: 1, second: 11)
case .jack, .queen, .king:
return Values(first: 10, second: nil)
default:
return Values(first: self.rawValue, second: nil)
}
}
}
// BlackjackCard 的屬性和方法
let rank: Rank, suit: Suit
var description: String {
var output = "suit is \(suit.rawValue)," output += " value is \(rank.values.first)" if let second = rank.values.second {
output += " or \(second)" }
return output
}
}let theAceOfSpades = BlackjackCard(rank: .ace, suit: .spades)print("theAceOfSpades: \(theAceOfSpades.description)")
// 打印“theAceOfSpades: suit is 1, value is 1 or 11”let heartsSymbol = BlackjackCard.Suit.hearts.rawValue
// 2擴展可以給一個現有的類,結構體,枚舉,還有協議添加新的功能。
Swift 中的擴展可以:
添加計算型實例屬性和計算型類屬性
定義實例方法和類方法
提供新的構造器
定義下標
定義和使用新的嵌套類型
使已經存在的類型遵循(conform)一個協議
擴展語法:
extension SomeType {
// 在這里給 SomeType 添加新的功能
}擴展可以給現有類型添加計算型實例屬性和計算型類屬性。
擴展可以給現有的類型添加新的構造器。
擴展可以給現有類型添加新的實例方法和類方法。
擴展可以給現有的類型添加新的下標。
擴展可以給現有的類,結構體,還有枚舉添加新的嵌套類型。
示例:
// 擴展的語法
extension SomeType {
// 在這里給 SomeType 添加新的功能
}
// 添加一個或多個協議
extension SomeType: SomeProtocol, AnotherProtocol {
// 協議所需要的實現寫在這里
}
struct Size {
var width = 0.0, height = 0.0
}
struct Point {
var x = 0.0, y = 0.0
}
struct Rect {
var origin = Point()
var size = Size()
}
extension Rect {
init(center: Point, size: Size) {
let originX = center.x - (size.width / 2)
let originY = center.y - (size.height / 3)
self.init(origin: Point(x: originX, y: originY), size: size)
}
}let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
size: Size(width: 3.0, height: 3.0))
// centerRect 的 origin 是 (2.5, 2.5) 并且它的 size 是 (3.0, 3.0)
extension Int {
func repetitions(task: () -> Void) {
for _ in 0..<self {
task()
}
}
}
3.repetitions {
print("Hello!")
}
// Hello!
// Hello!
// Hello!
extension Int {
mutating func square() {
self = self * self
}
}
var somtInt = 3
someInt.square()
// someInt 現在是9協議定義了一個藍圖,規定了用來實現某一特定任務或者功能的方法、屬性,以及其他需要的東西。
類、結構體或枚舉都可以遵循協議,并為協議定義的這些要求提供具體實現。
協議語法
protocol SomeProtocol {
// 這里是協議的定義部分
}協議可以要求遵循協議的類型提供特定名稱和類型的實例屬性或類型屬性。
協議可以要求遵循協議的類型實現某些指定的實例方法或類方法。
在值類型(即結構體和枚舉)的實例方法中,將 mutating 關鍵字作為方法的前綴,寫在 func 關鍵字之前,表示可以在該方法中修改它所屬的實例以及實例的任意屬性的值。
協議可以要求遵循協議的類型實現指定的構造器。
委托是一種設計模式,它允許類或結構體將一些需要它們負責的功能委托給其他類型的實例。
示例:
// 協議語法
protocol SomeProtocol {
// 這里是協議的定義部分
}
struct SomeStructure: FirstProtocol, AnotherProtocol {
// 這里是結構體的定義部分
}
class SomeClass: SomeSuperClass, FirstProtocol, AnotherProtocol {
// 這里是類的定義部分
}
protocol SomeProtocol {
var mustBeSettable: Int { get set }
var doesNotNeedToBeSettable: Int { get }
}
protocol AnotherProtocol {
static var someTypeProperty: Int { get set }
}
protocol FullyNamed {
var fullName: String { get }
}
struct person: FullyNamed {
var fullName: String
}let john = Person(fullName: "John Appleseed")
// john.fullName 為 "John Appleseed"class Starship: FullyNamed {
var prefix: String?
var name: String
init(name: String, prefix: String? = nil) {
self.name = name
self.prefix = prefix
}
var fullName: String {
return (prefix != nil ? prefix! + " " : "") + name
}
}
var ncc1701 = Starship(name: "Enterprise", prefix: "USS")
// ncc1701.fullName 為 "USS Enterprise"泛型代碼讓你能根據自定義的需求,編寫出適用于任意類型的、靈活可復用的函數及類型。
你可避免編寫重復的代碼,而是用一種清晰抽象的方式來表達代碼的意圖。
示例:
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
let temporaryA = a
a = b
b = temporaryA
}
func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
let temporaryA = a
a = b
b = temporaryA
}
func swapTwoInts(_ a: inout Int, _ b: inout Int)
func swapTwoValues<T>(_ a: inout T, _ b: inout T)
var someInt = 3
var anotherInt = 107
swapTwoValues(&someInt, &anotherInt)
// someInt 現在是 107,anotherInt 現在是 3
var someString = "hello"var anotherString = "world"swapTwoValues(&someString, &anotherString)
// someString 現在是“world”,anotherString 現在是“hello”具有不透明返回類型的函數或方法會隱藏返回值的類型信息。
函數不再提供具體的類型作為返回類型,而是根據它支持的協議來描述返回值。
在處理模塊和調用代碼之間的關系時,隱藏類型信息非常有用,因為返回的底層數據類型仍然可以保持私有。
不透明類型和泛型相反。不透明類型允許函數實現時,選擇一個與調用代碼無關的返回類型。
如果函數中有多個地方返回了不透明類型,那么所有可能的返回值都必須是同一類型。返回不透明類型和返回協議類型主要區別,就在于是否需要保證類型一致性。
一個不透明類型只能對應一個具體的類型,即便函數調用者并不能知道是哪一種類型;協議類型可以同時對應多個類型,只要它們都遵循同一協議。
示例:
protocol Shape {
func draw() -> String
}
struct Triangle: Shape {
var size: Int
func draw() -> String {
var result = [String]()
for length in 1...size {
result.append(String(repeating: "*", count: length))
}
return result.joined(separator: "\n")
}
}let smallTriangle = Triangle(size: 3)print(smallTriangle.draw())
// *
// **
// ***
struct FlippedShape<T: Shape>: Shape {
var shape: T
func draw() -> String {
let lines = shape.draw().split(separator: "\n")
return lines.reversed().joined(separator: "\n")
}
}let flippedTriangle = FlippedShape(shape: smallTriangle)print(flippedTriangle.draw())
// ***
// **
// *Swift 使用自動引用計數(ARC)機制來跟蹤和管理你的應用程序的內存。
如果兩個類實例互相持有對方的強引用,因而每個實例都讓對方一直存在,就是這種情況。這就是所謂的循環強引用。
Swift提供了兩種辦法用來解決你在使用類的屬性時所遇到的循環強引用問題:弱引用(weak reference)和無主引用(unowned reference)。
聲明屬性或者變量時,在前面加上 weak 關鍵字表明這是一個弱引用。
聲明屬性或者變量時,在前面加上關鍵字 unowned 表示這是一個無主引用。
示例:
// 自動引用計數實踐
class Person {
let name: String
init(name: String) {
self.name = name
print("\(name) is being initialized")
}
deinit {
print("\(name) is being deinitialized")
}
}
var reference1: Person?
var reference2: Person?
var reference3: Person?
reference1 = Person(name: "John Appleseed")
// 打印“John Appleseed is being initialized”
reference2 = reference1
reference3 = reference1
reference1 = nil
reference2 = nil
reference3 = nil
// 打印“John Appleseed is being deinitialized”
// 循環強引用
class Person {
let name: String
init(name: String) { self.name = name }
var apartment: Apartment?
deinit { print("\(name) is being deinitialized") }
}
class Apartment {
let unit: String
init(unit: String) { self.unit = unit }
var tenant: Person?
deinit { print("Apartment \(unit) is being deinitialized") }
}
var john: Person?
var unit4A: Apartment?
john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")
john = nil
unit4A = nil
// 弱引用
class Person {
let name: String
init(name: String) { self.name = name }
var apartment: Apartment?
deinit { print("\(name) is being deinitialized") }
}
class Apartment {
let unit: String
init(unit: String) { self.unit = unit }
weak var tenant: Person?
deinit { print("Apartment \(unit) is being deinitialized") }
}
var john: Person?
var unit4A: Apartment?
john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")
john!.apartment = unit4A
unit4A!.tenant = john
john = nil
// 打印“John Appleseed is being deinitialized”默認情況下,Swift 會阻止你代碼里不安全的行為。
示例:
func balance(_ x: inout Int, _ y: inout Int) {
let sum = x + y
x = sum / 2
y = sum - x
}
var playerOneScore = 42
var playerTwoScore = 30
balance(&playerOneScore, &playerTwoScore) // 正常
balance(&playerOneScore, &playerOneScore)
// 錯誤:playerOneScore 訪問沖突訪問控制可以限定其它源文件或模塊對你的代碼的訪問。
open 和 public 級別可以讓實體被同一模塊源文件中的所有實體訪問,在模塊外也可以通過導入該模塊來訪問源文件里的所有實體。通常情況下,你會使用 open 或 public 級別來指定框架的外部接口。
internal 級別讓實體被同一模塊源文件中的任何實體訪問,但是不能被模塊外的實體訪問。通常情況下,如果某個接口只在應用程序或框架內部使用,就可以將其設置為 internal 級別。
fileprivate 限制實體只能在其定義的文件內部訪問。如果功能的部分實現細節只需要在文件內使用時,可以使用 fileprivate 來將其隱藏。
private 限制實體只能在其定義的作用域,以及同一文件內的 extension 訪問。如果功能的部分細節只需要在當前作用域內使用時,可以使用 private 來將其隱藏。
open 為最高訪問級別(限制最少),private 為最低訪問級別(限制最多)。
open 只能作用于類和類的成員,它和 public 的區別主要在于 open 限定的類和成員能夠在模塊外能被繼承和重寫。
示例:
public class SomePublicClass {}
internal class SomeInternalClass {}
fileprivate class SomeFilePrivateClass {}
private class SomePrivateClass {}
class SomeInternalClass {} // 隱式 internal
var someInternalConstant = 0 // 隱式 internal
public class SomePublicClass { // 顯式 public 類
public var somePublicProperty = 0 // 顯式 public 類成員
var someInternalProperty = 0 // 隱式 internal 類成員
fileprivate func someFilePrivateMethod() {} // 顯式 fileprivate 類成員
private func somePrivateMethod() {} // 顯式 private 類成員
}
class SomeInternalClass { // 隱式 internal 類
var someInternalProperty = 0 // 隱式 internal 類成員
fileprivate func someFilePrivateMethod() {} // 顯式 fileprivate 類成員
private func somePrivateMethod() {} // 顯式 private 類成員
}
fileprivate class SomeFilePrivateClass { // 顯式 fileprivate 類
func someFilePrivateMethod() {} // 隱式 fileprivate 類成員
private func somePrivateMethod() {} // 顯式 private 類成員
}
private class SomePrivateClass { // 顯式 private 類
func somePrivateMethod() {} // 隱式 private 類成員
}Swift還提供了數種可以對數值進行復雜運算的高級運算符。它們包含了位運算符和移位運算符。
示例:
let initialBits: UInt8 = 0b00001111let invertedBits = ~initialBits // 等于 0b11110000
var potentialOverflow = Int16.max
// potentialOverflow 的值是 32767,這是 Int16 能容納的最大整數
potentialOverflow += 1
// 這里會報錯
struct Vector2D {
var x = 0.0, y = 0.0
}
extension Vector2D {
static func + (left: Vector2D, right: Vector2D) -> Vector2D {
return Vector2D(x: left.x + right.x, y: left.y + right.y)
}
}let vector = Vector2D(x: 3.0, y: 1.0)let anotherVector = Vector2D(x: 2.0, y: 4.0)let combinedVector = vector + anotherVector
// combinedVector 是一個新的 Vector2D 實例,值為 (5.0, 5.0)到此,相信大家對“什么是Swift語法”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。