Swift知识点

? 和 !(可选项)

?代表变量可为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))

类有而结构体没有的额外功能:

  1. 继承允许一个类继承另一个类的特征;
  2. 类型转换允许你在运行检查和解释一个类实例的类型;
  3. 反初始化器允许一个类实例释放任何其所被分配的资源;
  4. 引用计数允许不止一个对类实例的引用。
  5. 结构体是值类型(拷贝传值),类是引用类型(引用传值)
    === 和!== 用于判断两个变量是否指向同一个实例(类似于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)
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容