? 和 !(可选项)
?代表变量可为nil(将变量变成了枚举,要么为值,要么为nil),!代表强制展开,直接取值,不可能为nil
var optionalInteger: Int?
var optionalInteger: Optional<Int> //等价于上面那行代码
if let constantName = someOptional { #可选绑定项,如果赋值失败就不进入循环
statements
}
let possibleString: String? = "An optional string."
let forcedString: String = possibleString! #requires an exclamation mark
let assumedString: String! = "An implicitly unwrapped optional string." #隐式展开
let implicitString: String = assumedString #no need for an exclamation mark
a ?? b #等价于 a != nil ? a! : b
类型安全
swift不支持隐式转换,使用Int(val)进行转换
元组
元组中可以包含任何类型的变量,常用于返回值。
let http404Error = (404, "Not Found")
let (code, message) = http404Error
print("\(code) " + message)
let(code, _) = http404Error #_表示不需要使用的变量
let (x, y) = (1, 2) #同时为两个变量赋值
区间
for index in 1...5 { #闭区间,包括5
print("\(index) times 5 is \(index * 5)")
}
for index in 1..<5 { #开区间,不包括5
print("\(index) times 5 is \(index * 5)")
}
for name in names[2...] { #单侧区间 2 to end
print(name)
}
for name in names[...2] { #单侧区间 start to 2
print(name)
}
String
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."
""" #用三个"标记多行string
#String不能用Int下标获取Character
print(str[str.index(str.startIndex, offsetBy: 8)])
print(str[str.index(before: str.endIndex)])
print(str[str.index(after: str.startIndex)])
#删除使用remove
let range = welcome.index(welcome.endIndex, offsetBy: -6)..<welcome.endIndex
welcome.removeSubrange(range) #范围删除
welcome.remove(at: welcome.index(before: welcome.endIndex)) #删除单个
#插入使用insert
var welcome = "hello"
welcome.insert("!", at: welcome.endIndex) #插入单个
welcome.insert(contentsOf: " there", at: welcome.index(before: welcome.endIndex)) #插入字符串
#子字符串Substring,子字符串重用了原来字符串的内存
let beginning = greeting[..<index] #beginning是Substring类型
let newString = String(beginning) #转换成String类型,开辟了新内存
#前后缀
let scene = "Act 1, hello world"
scene.hasPrefix("Act 1")
scene.hasSuffix("world")
集合类型
#数组
var someInts = Array<Int>() #创建空数组
var someInts = [Int]()
var shoppingList: [String] = ["Eggs", "Milk"] #字面量创建数组
var threeDoubles = Array(repeating: 0.0, count: 3) #使用默认值创建数组
shoppingList[4...6] = ["Bananas", "Apples"] #将4-6的元素替换成新的集合
#插入删除
shoppingList.insert("Maple Syrup", at: 0)
let mapleSyrup = shoppingList.remove(at: 0)
for (index, value) in shoppingList.enumerated() { #enumerated()同时返回index和值
print("Item \(index + 1): \(value)")
}
#Set
var letters = Set<Character>() #空集合
letters.sorted() #排序
oddDigits.union(evenDigits) #并
oddDigits.intersection(evenDigits) #交
oddDigits.subtracting(singleDigitPrimeNumbers) #减
oddDigits.symmetricDifference(singleDigitPrimeNumbers) #与非
#字典
var namesOfIntegers = [Int: String]() #空字典
var airports: [String: String] = ["YYZ": "Toronto Pearson", "DUB": "Dublin"] #字面量创建字典
let oldValue = airports.updateValue("Dublin Airport", forKey: "DUB") #更新字典,返回旧值(String?),如果key不存在则新建一条(此时返回nil)
airports["APL"] = nil #删除一条
let removedValue = airports.removeValue(forKey: "DUB") #删除一条,失败返回nil
#遍历
for (airportCode, airportName) in airports {
print("\(airportCode): \(airportName)")
}
for airportCode in airports.keys { #遍历keys, airport.values遍历value
print("Airport code: \(airportCode)")
}
let airportCodes = [String](airports.keys) #将keys输出为数组
For循环
for name in names { #遍历数组
print("Hello, \(name)!")
}
for (animalName, legCount) in numberOfLegs { #遍历map
print("\(animalName)s have \(legCount) legs")
}
for index in 1...5 { #遍历数字, 也可用1..<5,此时不包含5
print("\(index) times 5 is \(index * 5)")
}
let minuteInterval = 5 #以一定间隔循环
for tickMark in stride(from: 0, to: minutes, by: minuteInterval) { #不包含minutes
// render the tick mark every 5 minutes (0, 5, 10, 15 ... 45, 50, 55)
}
for tickMark in stride(from: 0, through: minutes, by: minuteInterval) { } #包含minutes
While循环
while condition { #先判断再执行
statements
}
repeat { #先执行再判断
statements
} while condition
Switch
let someCharacter: Character = "z"
switch someCharacter {
case "a":
print("The first letter of the alphabet") #自带break,不会继续执行下一个case
case 1..<5: #区间匹配
...
case (_, 0): #元组匹配 或者case (1, 1)
...
case (-2...2, -2...2): #元组匹配加区间匹配
...
fallthrough #贯穿,此时继续执行下一个case
case "y", "z": #复合状态
print("The last letter of the alphabet")
default:
print("Some other character")
}
#标签
gameLoop: while square != finalSquare { #命名while循环为gameLoop
diceRoll += 1
if diceRoll == 7 { diceRoll = 1 }
switch square + diceRoll {
case finalSquare:
break gameLoop #跳出while循环
case let newSquare where newSquare > finalSquare:
continue gameLoop
default:
square += diceRoll
square += board[square]
}
}
print("Game over!")
Guard
在满足条件后代码会继续执行,否则执行else代码块
guard let name = person["name"] else {
return
}
函数
#使用元组作为返回值
func minMax(array: [Int]) -> (min: Int, max: Int) {
var currentMin = array[0]
var currentMax = array[0]
#...
return (currentMin, currentMax)
}
let bounds = minMax(array: [1,2,3])
#bounds.min == 1
#bounds.max == 3
func minMax(array: [Int]) -> (min: Int, max: Int)? { #可选元组
if array.isEmpty { return nil } //返回值可为空
#...
}
# 形参名和实参名
func greet(person: String, from hometown: String) -> String {
return "Hello \(person)! Glad you could visit from \(hometown)."
} # from是实参名,hometown是形参名
print(greet(person: "Bill", from: "Cupertino"))
func someFunction(_ firstParameterName: Int, secondParameterName: Int) {
#...
} # _ 表示省略实参名,之后可直接传入数据
someFunction(1, secondParameterName: 2)
# 可变形参
func arithmeticMean(_ numbers: Double...) -> Double { # 使用...表现可变形参
var total: Double = 0
for number in numbers {
total += number
}
return total / Double(numbers.count)
} # 此时numbers是[Double]数组
# 输入输出形参
func swapTwoInts(_ a: inout Int, _ b: inout Int) { # 使用inout关键字(类似C++引用)
let temporaryA = a
a = b
b = temporaryA
} # 此时传入参数会被实际改变
var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt) # 传入的时候要加&
# 函数类型
func addTwoInts(_ a: Int, _ b: Int) -> Int {
return a + b
} # addTwoInts的函数类型是(Int, Int) -> Int
var mathFunction: (Int, Int) -> Int = addTwoInts # 可以像其他类型一样设置函数变量,也可以写成var mathFunction = addTwoInts
print("Result: \(mathFunction(2, 3))")
# 函数类型作为形参
func printMathResult(_ mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) { # 函数类型变量作为形参
print("Result: \(mathFunction(a, b))")
}
printMathResult(addTwoInts, 3, 5)
# 函数类型作为返回值
func stepForward(_ input: Int) -> Int {
return input + 1
}
func stepBackward(_ input: Int) -> Int {
return input - 1
}
func chooseStepFunction(backwards: Bool) -> (Int) -> Int { # 返回函数类型
return backwards ? stepBackward : stepForward
}
var currentValue = 3
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
# 内嵌函数
func chooseStepFunction(backward: Bool) -> (Int) -> Int { #内嵌函数也能捕获夫函数中的变量
func stepForward(input: Int) -> Int { return input + 1 } # 在函数内部声明函数
func stepBackward(input: Int) -> Int { return input - 1 }
return backward ? stepBackward : stepForward
}
闭包
闭包能捕获上下文中的常量和变量
{ (parameters) -> (return type) in
statements
}
#第一种方法是写一个函数,然后传入sorted(by:)
func backward(_ s1: String, _ s2: String) -> Bool {
return s1 > s2
}
var reversedNames = names.sorted(by: backward)
#闭包版本
reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
return s1 > s2
})
#简写版本
reversedNames = names.sorted(by: { s1, s2 in return s1 > s2 } ) #可以去掉形参类型和返回类型,根据上下文自动判断
reversedNames = names.sorted(by: { $0 > $1 } ) #使用$x表示第x个形参,可以直接写函数体
#逃逸闭包
var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) { #需要加@escaping关键字
completionHandlers.append(completionHandler) #闭包被返回出函数
}
#自动闭包
var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
func serve(customer customerProvider: () -> String) {
print("Now serving \(customerProvider())!")
} #普通闭包
serve(customer: { customersInLine.remove(at: 0) } ) #调用时需要{ }
func serve(customer customerProvider: @autoclosure () -> String) {
print("Now serving \(customerProvider())!")
} #自动闭包,使用@autoclosure关键字
serve(customer: customersInLine.remove(at: 0)) #调用时不需要{ }
枚举
enum CompassPoint {
case north // 要写case,C++中不写
case south // 新行不用逗号隔开,C++需要
case east
case west
} // 最后不用; C++需要
var directionToHead = CompassPoint.west //声明时需要枚举名
directionToHead = .east // 之后再使用可以不写枚举名
for compass in CompassPoint.allCases { //使用allCases来遍历所有枚举
print(compass)
}
//关联值
enum Barcode {
case upc(Int, Int, Int, Int)
case qrCode(String)
}
var productBarcode = Barcode.upc(8, 85909, 51226, 3) //声明upc形式
productBarcode = .qrCode("ABCDEFGHIJKLMNOP") //改为qrCode模式,upc被替换
switch productBarcode {
case .upc(let numberSystem, let manufacturer, let product, let check): //取出枚举关联的值
print("UPC: \(numberSystem), \(manufacturer), \(product), \(check).")
case let .qrCode(productCode): //另一种写法,let在外
print("QR code: \(productCode).")
}
// 原始值
enum Planet: Int {
case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune //原始值为Int,从1开始
}
let positionToFind = 11
if let somePlanet = Planet(rawValue: positionToFind) { //rawValue返回Planet?
//...
}
// 递归枚举
indirect enum ArithmeticExpression { //使用indirect关键字
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))
类
类有而结构体没有的额外功能:
- 继承允许一个类继承另一个类的特征;
- 类型转换允许你在运行检查和解释一个类实例的类型;
- 反初始化器允许一个类实例释放任何其所被分配的资源;
- 引用计数允许不止一个对类实例的引用。
- 结构体是值类型(拷贝传值),类是引用类型(引用传值)
=== 和!== 用于判断两个变量是否指向同一个实例(类似于C++两个指针指向同一个对象)
Swift 的 String , Array 和 Dictionary类型是作为结构体来实现的,使用拷贝传值
属性
//延迟属性(懒加载)
class DataImporter {
var fileName = "data.txt"
// ...
}
class DataManager {
lazy var importer = DataImporter() //使用lazy关键字
var data = [String]()
//...
}
let manager = DataManager()
manager.data.append("Some data") //此时仍没加载DataImporter
print(manager.importer.fileName) //只有在第一次使用importer的时候才会加载
//计算属性
struct Rect {
var origin = Point()
var size = Size()
var center: Point { //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 volume: Double { //只读属性,只有get函数(简写)
return size * depth
}
}
//属性观察者
class StepCounter {
var totalSteps: Int = 0 { //全局变量也可以设置观察者
willSet(newTotalSteps) { //willSet是在赋值之前触发
print("About to set totalSteps to \(newTotalSteps)")
}
didSet { //didSet在赋值之后触发
if totalSteps > oldValue {
print("Added \(totalSteps - oldValue) steps")
}
}
}
}
let stepCounter = StepCounter()
stepCounter.totalSteps = 200
stepCounter.totalSteps = 360
//类型属性(静态成员)
struct SomeStructure {
static var storedTypeProperty = "Some value." //使用static关键字
static var computedTypeProperty: Int {
return 1
}
}
print(SomeStructure.storedTypeProperty) //使用的时候 类名.属性名
//类方法
class SomeClass {
class func someTypeMethod() { //使用class关键字
// type method implementation goes here
}
}
SomeClass.someTypeMethod() //使用的时候 类名.方法名
//内嵌类型
struct BlackjackCard {
// nested Suit enumeration
enum Suit: Character {
case Spades = "♠", Hearts = "♡", Diamonds = "♢", Clubs = "♣"
}
}
下标
subscript(index: Int) -> Int { //使用关键字subscript ,输入类型Int, 返回类型不定
get {
// return an appropriate subscript value here
}
set(newValue) {
// perform a suitable setting action here
}
}
继承
class Train: Vehicle {
override func makeNoise() { //重写方法
print("Choo Choo")
}
}
final class Car: Vehicle { // final关键字表示此类不能被继承
var gear = 1
override var description: String { //重写get函数
return super.description + " in gear \(gear)"
}
final func makeNoise() { //final关键字
print("Tu Tu")
}
}
初始化(构造函数)
struct Celsius {
var temperatureInCelsius: Double
let text: String
init(fromFahrenheit fahrenheit: Double) {
temperatureInCelsius = (fahrenheit - 32.0) / 1.8
text = "Fahrenheit" //常量可在init()函数中赋值,之后不可改变
}
init(fromKelvin kelvin: Double) {
temperatureInCelsius = kelvin - 273.15
text = "Kelvin"
}
init(_ celsius: Double) { //隐藏参数名形式
temperatureInCelsius = celsius
}
}
let bodyTemperature = Celsius(37.0) //直接传参数
//结构体的成员初始化器
struct Size {
var width = 0.0, height = 0.0
}
let twoByTwo = Size(width: 2.0, height: 2.0) //编译器自动生成init(width: height:)初始化方法
//初始化器委托
struct Rect {
var origin = Point()
var size = Size()
init() {}
init(origin: Point, size: Size) {
self.origin = origin
self.size = size
}
init(center: Point, size: Size) {
let originX = center.x - (size.width / 2)
let originY = center.y - (size.height / 2)
self.init(origin: Point(x: originX, y: originY), size: size) //使用init(origin: ,size:)初始化,类似于C++
}
}
//指定初始化器和便捷初始化器
class Food {
var name: String
init(name: String) { //指定初始化器
self.name = name
}
convenience init() { //便捷初始化器
self.init(name: "[Unnamed]") //便捷初始化器调用指定初始化器,前面加convenience关键字
}
}
class RecipeIngredient: Food {
var quantity: Int
init(name: String, quantity: Int) { //指定初始化器
self.quantity = quantity //先初始化自己的属性,再调用父类初始化器
super.init(name: name) //调用父类指定初始化器
self.name += "_1" //调用父类初始化器后才可以重新给基础属性赋值
}
override convenience init(name: String) { //便携初始化器
self.init(name: name, quantity: 1)
quantity -= 1 //便携初始化器要先调用其他初始化器,然后再对属性重新赋值
}
}
class ShoppingListItem: RecipeIngredient { //没有重写初始化器,自动继承父类的所有初始化器
var purchased = false
var description: String {
var output = "\(quantity) x \(name)"
output += purchased ? " ✔" : " ✘"
return output
}
}
//可失败初始化器
struct Animal {
let species: String
init?(species: String) { //init?表示可失败初始化器,其可被子类的不可失败初始化器override
if species.isEmpty { return nil } //return nil表示初始化失败
self.species = species
}
}
//必要初始化器
class SomeClass {
required init() { //使用required关键字
// initializer implementation goes here
}
}
class SomeSubclass: SomeClass {
required init() { //其子类必须override这个初始化器, 前面不需要override关键字
// subclass implementation of the required initializer goes here
}
}
//使用闭包给属性赋默认值
struct Chessboard {
let boardColors: [Bool] = {
var temporaryBoard = [Bool]()
var isBlack = false
for i in 1...8 {
for j in 1...8 {
temporaryBoard.append(isBlack)
isBlack = !isBlack
}
isBlack = !isBlack
}
return temporaryBoard
}() //{ }后跟()表示立即执行此闭包
func squareIsBlackAt(row: Int, column: Int) -> Bool {
return boardColors[(row * 8) + column]
}
}
反初始化器(析构函数)
使用deinit关键字,因为swift使用ARC,所以一般不需要自己手动释放内存,只有在有特殊任务要在销毁对象时处理的时候才会实现反初始化器
ARC 自动引用计数
可能遇到循环强引用的问题,此时需要弱引用或无主引用解除循环。(对于生命周期中会变为 nil 的实例使用弱引用。对于初始化赋值后再也不会被赋值为 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? #弱应用使用weak关键字,tenant可为nil
deinit { print("Apartment \(unit) is being deinitialized") }
}
# 无主引用
class Customer {
let name: String
var card: CreditCard?
init(name: String) {
self.name = name
}
deinit { print("\(name) is being deinitialized") }
}
class CreditCard {
let number: UInt64
unowned let customer: Customer # 无主引用使用unowned关键字,customer不可为nil
init(number: UInt64, customer: Customer) {
self.number = number
self.customer = customer
}
deinit { print("Card #\(number) is being deinitialized") }
}
#闭包和self循环强引用
lazy var someClosure: () -> String = {
[unowned self, weak delegate = self.delegate!] in #将self设置为unowned,
// closure body goes here
}
lazy var asHTML: () -> String = {
[unowned self] in # 加上这句话保证没有循环强引用
if let text = self.text {
return "<\(self.name)>\(text)</\(self.name)>"
} else {
return "<\(self.name) />"
}
}
可选链
如果通过可选链取回一个 Int 值,就一定会返回 Int? ,不论通过了多少层的可选链;
如果通过可选链访问 Int? 值, Int? 一定就是返回的类型,无论通过了多少层的可选链。
class Person {
var residence: Residence?
}
class Residence {
var numberOfRooms = 1
func printNumberOfRooms() {
print("The number of rooms is \(numberOfRooms)")
}
}
if let roomCount = john.residence?.numberOfRooms { #如果residence为nil,返回nil
print("John's residence has \(roomCount) room(s).")
} else {
print("Unable to retrieve the number of rooms.")
}
if john.residence?.printNumberOfRooms() != nil { #函数也可以放入可选链中判定是否为nil
print("It was possible to print the number of rooms.")
} else {
print("It was not possible to print the number of rooms.")
}
错误处理
func canThrowErrors() throws -> String //抛出函数,在形参后面加throws关键字
enum VendingMachineError: Error { //继承Error类来定义Error类型
case invalidSelection
case insufficientFunds(coinsNeeded: Int)
case outOfStock
}
func vend(itemNamed name: String) throws {
guard let item = inventory[name] else { //guard进行条件判断
throw VendingMachineError.invalidSelection
}
}
func buyFavoriteSnack(person: String, vendingMachine: VendingMachine) throws {
let snackName = favoriteSnacks[person] ?? "Candy Bar"
try vendingMachine.vend(itemNamed: snackName) //使用try来获取错误
}
var vendingMachine = VendingMachine()
vendingMachine.coinsDeposited = 8
do { //使用do-catch获取错误
try buyFavoriteSnack("Alice", vendingMachine: vendingMachine) //如果通过,执行下面的代码
// Enjoy delicious snack
} 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.")
}
let x = try? someThrowingFunction() //如果try失败,返回nil
// 延迟执行
func processFile(filename: String) throws {
if exists(filename) {
let file = open(filename)
defer { // 使用defer关键字
close(file) //此段代码会在作用域最后执行
}
while let line = try file.readline() {
// Work with the file.
}
// close(file) is called here, at the end of the scope.
}
}
类型转换
var movieCount = 0
var songCount = 0
for item in library {
if item is Movie { //使用is判断实例是否是某类型
movieCount += 1
} else if item is Song {
songCount += 1
}
}
//向下类型转换
for item in library {
if let movie = item as? Movie { //可选项转换, as?, 如果失败返回nil
print("Movie: '\(movie.name)', dir. \(movie.director)")
} else if let song = item as! Song { //强制项转换, as!, 如果失败编译报错
print("Song: '\(song.name)', by \(song.artist)")
}
}
//Any, AnyObject
var things = [Any]() //Any代表任何类型,AnyObject表示任何类型的实例
things.append(0)
things.append(0.0)
things.append(42)
things.append(3.14159)
things.append("hello")
things.append((3.0, 5.0))
things.append(Movie(name: "Ghostbusters", director: "Ivan Reitman"))
things.append({ (name: String) -> String in "Hello, \(name)" })
扩展
extension Double { // extension加类名
var km: Double { return self * 1_000.0 }
var m: Double { return self }
}
协议
protocol FullyNamed { // 使用protocol关键字
var fullName: String { get } //要求类必须有一个fullName变量
func random() -> Double //要求实现函数
}
struct Person: FullyNamed { // 使用: ProtocolName来给类添加协议
var fullName: String
//...
func random() -> Double { //实现协议函数
lastRandom = ((lastRandom * a + c).truncatingRemainder(dividingBy:m))
return lastRandom / m
}
}
class Dice {
let sides: Int
let generator: FullyNamed //将协议作为类型,此变量可以等于任何实现了该协议的实例
}
//在扩展中添加协议
protocol TextRepresentable {
var textualDescription: String { get }
}
extension Dice: TextRepresentable { //将协议实现在扩展中,即使没有原始类的源代码也能使其遵守协议
var textualDescription: String {
return "A \(sides)-sided dice"
}
}
protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol { //类专用的协议,前面加AnyObject
// class-only protocol definition goes here
}
泛型(C++模板)
func swapTwoValues<T>(_ a: inout T, _ b: inout T) { //函数名后加<T> , T作为类型
let temporaryA = a
a = b
b = temporaryA
}
swapTwoValues(&someInt, &anotherInt) // 使用时会自动推断类型
struct Stack<Element> { //泛型结构体
var items = [Element]()
mutating func push(_ item: Element) { //mutating表示异变(只在结构体中使用),此函数可改变结构体属性值,
items.append(item)
}
mutating func pop() -> Element {
return items.removeLast()
}
}
var stackOfStrings = Stack<String>() //使用的时候注明类型
stackOfStrings.push("uno")
extension Stack { //扩展泛型结构不需要加类型
var topItem: Element? {
return items.isEmpty ? nil : items[items.count - 1]
}
}
//泛型限定
func findIndex<T: Equatable>(of valueToFind: T, in array:[T]) -> Int? { //T: Equatable 限定T必须遵守Equatable协议
for (index, value) in array.enumerated() {
if value == valueToFind {
return index
}
}
return nil
}
访问控制
public class SomePublicClass {} //最开放访问级别,所有模块都可访问
internal class SomeInternalClass {} //默认访问级别,同模块内可访问
fileprivate class SomeFilePrivateClass {} //文件内可访问
private class SomePrivateClass {} //类内可访问
位运算符
左右移动
无符号数直接移动,越界抛弃,末尾补0
有符号数中,负数存储的是 2 的 n 次方减去它的绝对值,n 为数值位的位数。一个 8 位的数有七个数值位,所以是 2 的 7 次方(128) 。此编码称为二进制补码,这种存储方式可使有符号数的左右移动行为和无符号数一致。(向右移动时,对产生的空位使用符号位填补)
let decimalInteger = 17
let binaryInteger = 0b10001 // 二进制的17, 0b
let octalInteger = 0o21 // 八进制的17, 0o
let hexadecimalInteger = 0x11 // 十六进制, 0x
let initialBits: UInt8 = 0b00001111
let invertedBits = ~initialBits // equals 11110000 // 取反
let firstBits: UInt8 = 0b00010100
let otherBits: UInt8 = 0b00000101
let outputBits = firstBits ^ otherBits // equals 00010001 // 异或,两位不相等时取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)
}
static prefix func - (vector: Vector2D) -> Vector2D { // prefix关键字表示这是一个前置运算符
return Vector2D(x: -vector.x, y: -vector.y)
}
static func += (left: inout Vector2D, right: Vector2D) { // 重载组合运算符,第一个算符要设为inout,然后没有返回值
left = left + right
}
}
extension Vector2D: Equatable { // 重载==要实现Equatable协议
static func == (left: Vector2D, right: Vector2D) -> Bool {
return (left.x == right.x) && (left.y == right.y)
}
}