匯編相關(guān)
lldb常用指令
//讀取寄存器的值
register read/格式
register read/
//修改寄存器的值
register write 寄存器名稱 數(shù)值
register write rax 0
//讀取內(nèi)存中的值
x/數(shù)量-格式-字節(jié)大小 內(nèi)存地址
x/3xw 0x0000010
//修改內(nèi)存中的值
memory write 內(nèi)存地址 數(shù)值
memory write 0x0000010 10
格式
x是16進(jìn)制蛙奖,f是浮點(diǎn)册倒,d是十進(jìn)制
字節(jié)大小
b-byte 1字節(jié)
h-half word 2字節(jié)
w-word 4字節(jié)
g-giant word 8字節(jié)
expreion 表達(dá)式
可以簡寫:expr 表達(dá)式
expreion $rax
expreion $rax = 1
po 表達(dá)式
print 表達(dá)式
po/x $rax
thread step-over筹误、next、n
單步運(yùn)行躯泰,把子函數(shù)當(dāng)做整體一步執(zhí)行(源碼級別)
thread step-in、step华糖、s
單步運(yùn)行麦向,遇到子函數(shù)會進(jìn)入子函數(shù)(源碼級別)
thread step-inst-over、nexti客叉、ni
單步運(yùn)行诵竭,把子函數(shù)當(dāng)做整體一步執(zhí)行(匯編級別)
thread step-inst话告、stepi、si
單步運(yùn)行卵慰,遇到子函數(shù)會進(jìn)入子函數(shù)(匯編級別)
thread step-out沙郭、finish
直接執(zhí)行完當(dāng)前函數(shù)的所有代碼,返回到上一個函數(shù)(遇到斷點(diǎn)會卡咨雅蟆)
規(guī)律
- 內(nèi)存地址格式為:0x4bdc(%rip), 一般是全局變量
- 內(nèi)存地址格式為:-0x78(%rbp), 一般是局部變量
- 內(nèi)存地址格式為:-0x10(%rax), 一般是堆空間
寄存器
有16個常用寄存器
- rax病线、rbx、rcx鲤嫡、rdx送挑、rsi、rdi泛范、rbp让虐、rsp
- r8、r9罢荡、r10赡突、r11、r12区赵、r13惭缰、r14、r15
寄存器的具體用途
- rax常作為函數(shù)返回值使用
- rsi笼才、rdi漱受、rdx、rcx骡送、r8昂羡、r9等寄存器常用于存放函數(shù)參數(shù)
- rsp、rbp用于棧操作
- rip作為指令指針
- 存儲著CPU下一條要執(zhí)行的指令地址
- 一旦CPU讀取一條指令摔踱,rip會自動指向下一條指令地址(存儲下一條指令地址)
Swift語法
- 被class修飾的計(jì)算類型屬性虐先,可以被子類重寫
- 被static修飾的類型屬性(存儲、計(jì)算)派敷,不可以被子類重寫
class Circle {
static var radius: Int = 0
class var diameter: Int {
set {
print("Circle setDiameter")
radius = newValue / 2
}
get {
print("Circle getDiameter")
return radius * 2
}
}
}
class SubCircle: Circle {
override static var diameter: Int {
set {
print("Circle setDiameter")
super.diameter = newValue>0 ? newValue : 0
}
get {
print("Circle getDiameter")
return super.diameter
}
}
}
Circle.radius = 6;
// Circle getDiameter
// 12
print(Circle.diameter)
//Circle setDiameter
Circle.diameter = 20
// 10
print(Circle.radius)
SubCircle.radius = 6
//SubCircle getDiameter
// Circle getDiameter
//12
print(SubCircle.diameter)
//SubCircle setDiameter
//Circle setDiameter
SubCircle.diameter = 20
//10
print(SubCircle.radius)
//字符串長度<= 0xF蛹批,字符串內(nèi)容直接存放在str1變量的存中
var str1 = "0123456789"
//字符串長度> 0xF, 字符串內(nèi)容存放在_TEXT.cstring中 (常量區(qū))
//字符串的地址值信息存放在str2變量的后8個字節(jié)中
var str2 = "0123456789ABCDEF"
//由于字符串長度<= 0xF,所以字符串內(nèi)容依然存放在str1變量的內(nèi)存中
str1.append("ABCDE")
//開辟堆空間
str1.append("F")
//開辟堆空間
str2.append("G")
運(yùn)算符重載
struct Point {
var x: Double = 0
var y: Double = 0
static func + (p1: Point, p2: Point) -> Point {
Point(x: p1.x + p2.x, y: p1.y + p2.y)
}
static func - (p1: Point, p2: Point) -> Point {
Point(x: p1.x - p2.x, y: p1.y - p2.y)
}
static prefix func - (p: Point) -> Point {
Point(x: -p.x, y: -p.y)
}
static func += (p1: inout Point, p2: Point) {
p1 = p1 + p2
}
static prefix func ++(p: inout Point) -> Point {
p += Point(x: 1, y: 1)
return p
}
static postfix func ++ (p: inout Point) -> Point {
let tmp = p
p += Point(x: 1, y: 1)
return tmp
}
static func == (p1: Point, p2: Point) -> Bool {
(p1.x == p2.x) && (p1.y == p2.y)
}
}
計(jì)算屬性篮愉、下標(biāo)方法腐芍、嵌套類型
extension Double {
var km: Double { self * 1_000.0 }
var m: Double { self }
var dm: Double { self / 10.0 }
var cm: Double { self / 100.0 }
var mm: Double { self / 1_000.0 }
}
extension Array {
subscript(nullable idx: Int) -> Element? {
if (startIndex..<endIndex).contains(idx) {
return self[idx]
}
return nil
}
}
extension Int {
func repetitions(task: () -> Void) -> Void {
for _ in 0..<self { task() }
}
mutating func square() -> Int {
self = self * self
return self
}
enum Kind { case negative, zero, postive }
var kind: Kind {
switch self {
case 0: return .zero
case let x where x > 0: return .postive
default: return .negative
}
}
subscript(digitIndex: Int) -> Int {
var decimalBase = 1
for _ in 0..< digitIndex { decimalBase *= 10 }
return (self / decimalBase) % 10
}
}
訪問控制( Access Control )
■ 在訪問權(quán)限控制這塊, Swift提供了5個不同的訪問級別(以下是從高到低排列,實(shí)體指被訪問級別修飾的內(nèi)容)
- open :允許在定義實(shí)體的模塊试躏、其他模塊中訪問,允許其他模塊進(jìn)行繼承猪勇、重寫( open只能用在類、類成員上)
- public :允許在定義實(shí)體的模塊颠蕴、其他模塊中訪問,不允許其他模塊進(jìn)行繼承埠对、重寫
- internal :只允許在定義實(shí)體的模塊中訪問,不允許在其他模塊中訪問
- fileprivate :只允許在定義實(shí)體的源文件中訪問
- private :只允許在定義實(shí)體的封閉聲明中訪問
■ 絕大部分實(shí)體默認(rèn)都是internal級別
訪問級別的使用準(zhǔn)則
■ 一個實(shí)體不可以被更低訪問級別的實(shí)體定義,比如
- 變量\常量類型 ≥ 變量\常量
- 參數(shù)類型络断、返回值類型 ≥ 函數(shù)
- 父類 ≥ 子類
- 父協(xié)議 ≥子協(xié)議
- 原類型 ≥ typealias
- 原始值類型、關(guān)聯(lián)值類型 ≥ 枚舉類型
- 定義類型A時用到的其他類型 ≥ 類型A
成員项玛、嵌套類型
■ 類型的訪問級別會影響成員(屬性貌笨、方法、初始化器襟沮、下標(biāo))锥惋、嵌套類型的默認(rèn)訪問級別
- 一般情況下,類型為private或fileprivate ,那么成員\嵌套類型默認(rèn)也是private或fileprivate
- 一般情況下,類型為internal或public ,那么成員\嵌套類型默認(rèn)是internal
public class PublicClass {
public var p1 = 0
var p2 = 0 // internal
fileprivate func f1() {} // fileprivate
private func f2() {} // private
}
class InternalClass { // internal
var p = 0 // internal
fileprivate func f1() {} // fileprivate
private func f2() {} // private
}
fileprivate class FilePrivateClass { // fileprivate
func f1() {} // fileprivate
private func f2() {} // private
}
private class PrivateClass { // private
func f() {} // private
}
■ 子類重寫的成員訪問級別必須 ≥ 父類的成員訪問級別
getter,setter
- getter, setter默認(rèn)自動接收他們所屬環(huán)境的訪問級別
■ 可以給setter單獨(dú)設(shè)置一個比getter更低的訪問級別 ,用以限制寫的權(quán)限
fileprivate(set) public var num = 10
class Person {
private(set) var age = 0
fileprivate(set) public var weight: Int {
set {}
get { 10 }
}
internal(set) public subscript(index: Int) -> Int {
set {}
get { index }
}
}
初始化器
■ 如果一個public類想在另一個模塊調(diào)用編譯生成的默認(rèn)無參初始化器,必須顯式提供public的無參初始化器
- 因?yàn)?strong>public類的默認(rèn)初始化器是interna1級別
■required初始化器必須跟它所屬類擁有相同的訪問級別
■如果結(jié)構(gòu)體有private\ fileprivate的存儲實(shí)例屬性,那么它的成員初始化器也是private\ fileprivate
- 否則默認(rèn)就是internal
協(xié)議
■ 協(xié)議中定義的要求自動接收協(xié)議的訪問級別,不能單獨(dú)設(shè)置訪問級別
- public協(xié)議定義的要求也是public
■ 協(xié)議實(shí)現(xiàn)的訪問級別必須 ≥ 類型的訪問級別,或者 ≥ 協(xié)議的訪問級別
■ 下面代碼能編譯通過么?
public protocol Runnable {
func run()
}
public class Person : Runnable {
func run() {}
}
//Method 'run()' must be declared public because it matches a requirement in public protocol 'Runnable'
擴(kuò)展
■ 在同一文件中的擴(kuò)展,可以寫成類似多個部分的類型聲明
口 在原本的聲明中聲明一個私有成員,可以在同一文件的擴(kuò)展中訪問它
口 在擴(kuò)展中聲明一個私有成員,可以在同一文件的其他擴(kuò)展中、原本聲明中訪問它
public class Person {
private func run0() {}
private func eat0() {
run0()
}
}
extension Person {
private func run1() {}
private func eat1() {
run1()
}
}
extension Person {
private func eat2() {
run1()
}
}
閉包的循環(huán)引用
■ 如果想在定義閉包屬性的同時引用self,這個閉包必須是lazy的(因?yàn)樵趯?shí)例初始化完畢之后才能引用self)
■ 閉包fn內(nèi)部如果用到了實(shí)例成員(屬性开伏、方法)
編譯器會強(qiáng)制要求明確寫出self
class Person {
lazy var fn: (()->()) = {
[weak self] in
self?.run()
}
func run() { print("run") }
deinit { print ("deinit") }
}
■ 如果lazy屬性是閉包調(diào)用的結(jié)果,那么不用考慮循環(huán)引用的問題(因?yàn)殚]包調(diào)用后,閉包的生命周期就結(jié)束了)
class Person {
var age: Int = 0
lazy var getAge: Int = {
self.age
}()
deinit { print("deinit") }
}
@escaping
■ 非逃逸閉包膀跌、逃逸閉包, 一般都是當(dāng)做參數(shù)傳遞給函數(shù)
■ 非逃逸閉包: 閉包調(diào)用發(fā)生在函數(shù)結(jié)束前,閉包調(diào)用在函數(shù)作用域內(nèi)
■ 逃逸閉包: 閉包有可能在函數(shù)結(jié)束后調(diào)用,閉包調(diào)用逃離了函數(shù)的作用域,需要通過@escaping聲明
import Dispatch
typealias Fn = () -> ()
// fn是非逃逸閉包
func test1(_ fn: Fn) { fn() }
// fn是逃逸閉包
var gFn: Fn?
func test2(_ fn: @escaping Fn) { gFn = fn }
■左邊的閉包fn內(nèi)部如果用到了實(shí)例成員(屬性、方法)
內(nèi)存訪問沖突 ( Conflicting Access to Memory )
■ 內(nèi)存訪問沖突會在兩個訪問滿足下列條件時發(fā)生:
- 至少一個是寫入操作
- 它們訪問的是同一塊內(nèi)存
- 它們的訪問時間重疊(比如在同一個函數(shù)內(nèi))
//不存在內(nèi)存訪問沖突
func plus(_ num: inout Int) -> Int { num + 1 }
var number = 1
number = plus (&number)
//存在內(nèi)存訪問沖突
// Simultaneous accees to ?x0, but modificat ion requires exclusive acce
var step = 1
func increment(_ num:inout Int) { num += step }
increment (&step)
//解決內(nèi)存訪問沖突
var copyOfStep = step
increment(©OfStep)
step = copyOfStep
func balance(_ x: inout Int,_ y: inout Int) {
let sum=x+y
x=sum/2
y=sum-x
}
var num1 = 42
var num2 = 30
balance(&num1, &num2) // 0K
balance(&num1, &num1) // Error
struct Player {
var name: String
var health: Int
var energy: Int
mutating func shareHealth(with teammate: inout Player) {
balance(&teammate.health, &health)
}
}
var oscar = Player(name: "Oscar", health: 10, energy: 10)
var maria = Player(name: "Maria", health: 5, energy: 10)
oscar.shareHealth(with: &maria) // 0K
oscar.shareHealth(with: &oscar) // Error
var tulpe = (health: 10, energy: 20)
// Error
balance(&tulpe.health, &tulpe.energy)
var holly = Player(name: "Holly", health: 10, energy: 10)
// Error
balance(&holly.health, &holly.energy)
■ 如果下面的條件可以滿足,就說明重疊訪問結(jié)構(gòu)體的屬性是安全的
- 你只訪問實(shí)例存儲屬性,不是計(jì)算屬性或者類屬性
- 結(jié)構(gòu)體是局部變量而非全局變量
- 結(jié)構(gòu)體要么沒有被閉包捕獲要么只被非逃逸閉包捕獲
// OK
func test() {
var tulpe = (health: 10, energy: 20)
balance (&tulpe.health, &tulpe.energy)
var holly = Player(name: "Holly", health: 10, energy: 10)
balance (&holly.health, &holly.energy)
}
test()
指針
■ Swift中也有專門的指針類型,這些都被定性為"Unsafe" (不安全的) , 常見的有以下4種類型
- UnsafePointer<Pointee> 類似于 const Pointee *
- UnsafeMutablePointer<Pointee> 類似于 Pointee *
- UnsafeRawPointer 類似于 const void *
- UnsafeMutableRawPointer 類似于 void *
var age = 10
func test1(_ ptr: UnsafeMutablePointer<Int>) {
ptr.pointee += 10
}
func test2(_ ptr: UnsafePointer<Int>) {
print(ptr.pointee)
}
test1(&age)
test2(&age) // 20
print(age) // 20
var age = 10
func test3(_ ptr: UnsafeMutableRawPointer) {
ptr.storeBytes(of: 20, as: Int.self)
}
func test4(_ ptr: UnsafeRawPointer) {
print(ptr.load(as: Int.self))
}
test3(&age)
test4(&age) // 20
print(age) // 20
var age = 10
var ptr = withUnsafePointer(to: &age) { (p) -> Int in
return 20
}
獲得某個變量的指針
var age = 11
var ptr1 = withUnsafeMutablePointer(to: &age) { $0 }
var ptr2 = withUnsafePointer(to: &age) { $0 }
ptr1.pointee = 22
print(ptr2.pointee) // 22
print(age) // 22
var ptr3 = withUnsafeMutablePointer(to: &age) { UnsafeMutableRawPointer($0) }
var ptr4 = withUnsafePointer(to: &age) { UnsafeRawPointer($0) }
ptr3.storeBytes(of: 33, as: Int.self)
print(ptr4.load(as: Int.self)) // 33
print(age) // 33
創(chuàng)建指針
var ptr1 = UnsafeRawPointer( bitPattern: 0x100001234)
// 創(chuàng)建
var ptr = malloc(16)
// 存
ptr?.storeBytes(of: 11, as: Int.self)
ptr?.storeBytes(of: 22, toByteOffset: 8, as: Int.self)
// 取
print((ptr?.load(as: Int.self))!) // 11
print((ptr?.load(fromByteOffset: 8, as: Int.self))!) // 22
free(ptr)
var ptr = UnsafeMutableRawPointer . allocate (byteCount: 16, alignment: 1)
ptr.storeBytes(of: 11, as: Int.self)
ptr.advanced(by: 8).storeBytes(of: 22, as: Int.self)
print(ptr.load(as: Int.self)) // 11
print(ptr.advanced(by: 8).load(as: Int.self)) // 22
ptr.deallocate()
指針間的轉(zhuǎn)換
var ptr = UnsafeMutableRawPointer . allocate(byteCount: 16, alignment: 1)
ptr.aumingMemoryBound(to: Int.self).pointee = 11
(ptr + 8).aumingMemoryBound(to: Double.self). pointee = 22.0
print(unsafeBitCast(ptr, to: UnsafePointer<Int>.self).pointee) // 11
print(unsafeBitCast(ptr + 8, to: UnsafePointer<Double>.self).pointee) // 22.0
ptr.deallocate()
- unsafeBitCast是忽略數(shù)據(jù)類型的強(qiáng)制轉(zhuǎn)換,不會因?yàn)閿?shù)據(jù)類型的變化而改變原來的內(nèi)存數(shù)據(jù)
- 類似于C++ 中的reinterpret_cast
class Person {}
var person = Person()
// personObjectAddre存儲的就是堆空間地址
var personObjectAddre = unsafeBitCast(person, to: UInt.self)
print(UnsafeRawPointer(bitPattern: personObjectAddre))
var p = unsafeBitCast(person, to: UnsafeRawPointer.self)
print(p)
字面量(Literal)
var age = 10
var isRed = false
var name = "Jack"
上面代碼中的10固灵、false, "Jack"就是字面量
■ 常見字面量的默認(rèn)類型
public typea lias IntegerLiteralType = Int
public typealias FloatLiteralType = Double
public typealias BooleanL iteralType = Bool
public typealias StringLiteralType = String
//可以通過typealias修改字 面量的默認(rèn)類型
typealias FloatLiteralType = Float
typealias IntegerLiteralType = UInt8
var age = 10 // UInt8
var height = 1.68 // Float
■ Swift自帶的絕大部分類型,都支持直接通過字面量進(jìn)行初始化
Bool捅伤、Int、Float巫玻、Double丛忆、String、Array仍秤、 Dictionary熄诡、 Set、Optional
字面量協(xié)議應(yīng)用
extension Int : ExpressibleByBooleanLiteral {
public init( booleanLiteral value: Bool) { self = value ? 1 : 0 }
}
var num: Int = true
print(num) // 1
//■有點(diǎn)類似于C+ +中的轉(zhuǎn)換構(gòu)造函數(shù)
class Student : ExpressibleByIntegerLiteral, ExpressibleByFloatLiteral, ExpressibleByStringLiteral,
CustomStringConvertible {
var name: String = ""
var score: Double = 0
required init(floatLiteral value: Double) { self.score = value }
required init( integerLiteral value: Int) { self.score = Double(value) }
required init(stringLiteral value: String) { self.name = value }
required init ( unicodeScalarLiteral value: String) { self.name = value }
required init (extendedGraphemeClusterLiteral value: String) { self.name = value }
var description: String { "name=\(name) , score=\(score)"}
}
var stu: Student = 90
print(stu) // name=, score=90.0
stu = 98.5
print(stu) // name=, score=98.5
stu = "Jack"
print(stu) // name=Jack, score=0.0
struct Point {
var x = 0.0, y = 0.0
}
extension Point : ExpressibleByArrayLiteral, ExpressibleByDictionaryLiteral {
init(arrayLiteral elements: Double...) {
guard elements.count > 0 else { return }
self.x = elements [0]
guard elements.count > 1 else { return }
self.y = elements [1]
}
init(dictionaryLiteral elements: (String, Double)...) {
for (k, v) in elements {
if k == "x" { self.x = v }
else if k == "y" { self.y = v}
}
}
}
var p: Point = [10.5, 20.5]
print(p) // Point(x: 10.5, y: 20.5)
p = ["x":11,"y":22]
print(p) // Point(x: 11.0, y: 22.0)
通配符模式 ( Wildcard Pattern )
■ _ 匹配任何值
■ _?匹配非nil值
enum Life {
case human(name: String, age:Int?)
case animal(name: String, age:Int?)
}
func check(_ life: Life) {
switch life {
case . human(let name, _) :
print ("human", name)
case . animal(let name,_?):
print("animal", name)
default:
print("other")
}
}
check( . human( name: "Rose", age: 20)) // human Rose
check( . human(name: "Jack", age: nil)) // human Jack
check( . animal(name: "Dog", age: 5)) // animal Dog
check( . animal( name: "Cat", age: nil)) // other
枚舉Caset模式 ( Enumeration Case Pattern )
- if case語句等價于只有1個case的switch語句
let age=2
//原來的寫法
if age >= 0 && age <= 9 {
print("[0, 9]")
}
//枚舉Case模式
if case 0...9 = age {
print("[0, 9]")
}
guard case 0...9 = age else { return }
print("[0, 9]")
switch age {
case 0...9: print("[0, 9]")
default: break
}
let ages: [Int?] = [2, 3, nil, 5]
for case nil in ages {
print("有nil")
break
} //有nil值
let points = [(1, 0), (2, 1), (3, 0)]
for case let(x, 0) in points {
print(x)
} // 1 3
可選模式 ( Optional Pattern )
let age: Int? = 42
if case .some(let x) = age { print(x) }
if case let x? = age { print(x) }
let ages: [Int?] = [nil, 2, 3, nil, 5]
for case let age? in ages {
print (age)
}// 2 3 5
for item in ages {
if let age = item {
print(age)
} //跟上面的for,效果是等價的
}
func check(_ num: Int?) {
switch num {
case 2?: print("2")
case 4?: print("4")
case 6?: print("6")
case _?: print("other")
case _: print("nil")
}
}
check(4) // 4
check(8) // other
check(nil) // nil
類型轉(zhuǎn)換模式 ( Type-Casting Pattern )
let num: Any = 6
switch num {
case is Int:
//編譯器依然認(rèn)為num是Any類型
print("is Int", num)
// case let n as Int:
// print("as Int", n + 1)
default:
break
}
class Animal { func eat() { print(type(of: self), "eat") } }
class Dog: Animal { func run() { print(type(of: self), "run") } }
class Cat: Animal { func jump() { print(type(of: self), "jump") } }
func check(_ animal: Animal) {
switch animal {
case let dog as Dog:
dog.eat()
dog.run()
case is Cat:
animal.eat()
default: break
}
}
// Dog eat
// Dog run
check(Dog())
// Cat eat
check(Cat())
表達(dá)式模式 ( Expression Pattern )
- 表達(dá)式模式在case中
let point = (1, 2)
switch point {
case (0, 0):
print("(0, 0) is at the origin.")
case (-2...2, -2...2):
print("(\(point.0), \(point.1)) is near the origin.")
default:
print("The point is at (\(point.0), \(point.1)).")
}// (1, 2) is near the origin.
自定義表達(dá)式模式
■ 可以通過重載運(yùn)算符,自定義表達(dá)式模式的匹配規(guī)則
struct Student {
var score = 0, name = ""
static func ~=(pattern: Int, value: Student) -> Bool { value.score >= pattern }
static func ~=(pattern: ClosedRange<Int>, value: Student) -> Bool { pattern.contains(value.score) }
static func ~=(pattern: Range<Int>, value: Student) -> Bool { pattern.contains (value.score) }
}
var stu = Student(score: 75, name: "Jack" )
switch stu {
case 100: print(">= 100")
case 90: print(">= 90")
case 80..<90: print("[80, 90)")
case 60..79: print("[60, 79]")
case 0: print(">= 0")
default: break
}// [60, 79]
if case 60 = stu {
print(">= 60")
} //>= 60
var info = (Student(score: 70, name: "Jack"), "及格")
switch info {
case let (60, text): print(text)
default: break
}//及格
extension String {
static func ~= (pattern: (String) -> Bool, value: String) -> Bool {
pattern(value)
}
}
func hasPrefix(_ s: String) -> ((String) -> Bool) { { $0.hasPrefix(s) } }
func hasSuffix(_ s: String) -> ((String) -> Bool) { { $0.hasSuffix(s) } }
var str = "jack"
switch str {
case hasPrefix("j"), hasSuffix("k"):
print("以j開頭诗力, 或以k結(jié)尾")
default: break
} // 以j開頭凰浮, 或以k結(jié)尾
func isEven(_ i: Int) -> Bool { i%2 == 0 }
func is0dd(_ i: Int) -> Bool { i%2 != 0 }
extension Int {
static func ~= (pattern: (Int) -> Bool, value: Int) -> Bool {
pattern( value )
}
}
var age = 10
switch age {
case isEven:
print(age, "是個偶數(shù)" )
case isOdd:
print(age, "是個奇數(shù)")
default: break
}
prefix operator ~>
prefix operator ~>=
prefix operator ~<
prefix operator ~<=
prefix func ~> (_ i: Int) -> ((Int) -> Bool) { {$0 > i} }
prefix func ~>= (_ i: Int) -> ((Int) -> Bool) { {$0 >= i} }
prefix func ~< (_ i: Int) -> ((Int) -> Bool) { {$0 < i} }
prefix func ~<= (_ i: Int) -> ((Int) -> Bool) { {$0 <= i} }
var age = 9
switch age {
case ~>=0, ~<=10:
print("1")
case ~>10, ~<20:
print("2")
default: break
} // [0, 10]
Where
// 可以使用where為模式匹配增加匹配條件
var data = (10, "Jack")
switch data {
case let (age, _) where age > 10:
print(data.1, "age>10" )
case let (age, _) where age > 0:
print(data.1, "age>0")
default: break
}
var ages = [10, 20, 44, 23, 55]
for age in ages where age > 30 {
print (age)
}//44 55
protocol Stackable { associatedtype Element }
protocol Container {
associatedtype Stack : Stackable where Stack.Element: Equatable
}
func equal<S1: Stackable, S2: Stackable>(_ s1: S1,_ s2: S2) -> Bool where S1.Element == S2.Element, S1.Element: Hashable {
return false
}
extension Container where Self.Stack.Element: Hashable {}
條件編譯
// 操作系統(tǒng): macOS\i0S\tvOS\watchOS\Linux\Android\Windows\FreeBSD
#if os(macOS) || os(iOS)
// CPU#LMJ: i386x&6_ _64(a rma rm64
#elseif arch(x86_64) || arch(arm64 )
// swift版本
#elseif swift(<5) && swift(>=3)
// 模擬器
#elseif targetEnvironment(simulator)
// 可以導(dǎo)入某模塊
#elseif canImport(Foundation)
#else
#endif
// debug模式
#if DEBUG
// release模式
#else
#endif
#if TEST
print("test")
#endif
#if OTHER
print("other")
#endif
打印
func log<T>(_ msg: T ,
file: NSString = #file,
line: Int = #line,
fn: String = #function) {
#if DEBUG
let prefix = "\(file. lastPathComponent)_\(line)_\(fn):"
print(prefix, msg)
#endif
}
系統(tǒng)版本檢測
if #available(iOS 10, macOS 10.12, *) {
//對于i0S平臺,只在i0S10及以苇本,上版本執(zhí)行
//對于mac0S平臺袜茧,只在mac0S 10. 12及以上版本執(zhí)行
//最后的*表示在其他所有平臺都執(zhí)行
}
API可用性說明
@available(iOS 10, macOS 10.15, *)
class PersonX {}
struct StudentX {
@available(*, unavailable, renamed: "study" )
func study_() {}
func study() {}
@available( iOS, deprecated: 11)
@available (macOS, deprecated: 10.12)
func run() {}
}
■ 更多用法參考
iOS程序的入口
//在AppDelegate上面默認(rèn)有個 @UIApplicationMain標(biāo)記 , 這表示
//編譯器自動生成入口代碼(main函數(shù)代碼),自動設(shè)置AppDelegate為APP的代理
//也可以刪掉 @UIApplicationMain , 自定義入口代碼 : 新建一個main.swift文件
import UIKit
class HYApplication : UIApplication {}
UIApplicationMain(CommandLine.argc,
CommandLine.unsafeArgv,
NSStringFromClass(HYApplication.self),
NSStringFromClass(AppDelegate.self))
Swift調(diào)用OC
新建1個橋接頭文件瓣窄,文件名格式默認(rèn)為:{targetName}-Bridging-Header.h
在{targetName}-Bridging-Header.h文件中#import "AEPerson.h" OC要暴露給Swift的內(nèi)容
注:Swift 項(xiàng)目創(chuàng)建OC文件時會提示你自動創(chuàng)建橋接頭文件
// OC中
int sum(int a, int b);
@interface AEPerson : NSObject
@property (nonatomic, assign) NSInteger age;
@property (nonatomic, copy) NSString *name;
- (instancetype)initWithAge:(NSInteger)age name:(NSString *)name;
+ (instancetype)personWithAge:(NSInteger)age name:(NSString *)name;
- (void)run;
+ (void)run;
- (void)eat:(NSString *)food other:(NSString *)other;
+ (void)eat:(NSString *)food other:(NSString *)other;
@end
@implementation AEPerson
- (instancetype)initWithAge:(NSInteger)age name:(NSString *)name {
if (self = [super init]) {
self.age = age;
self.name = name;
}
return self;
}
+ (instancetype)personWithAge:(NSInteger)age name:(NSString *)name {
return [[self alloc] initWithAge:age name:name];
}
+ (void)run { NSLog(@"Person +run"); }
- (void)run { NSLog(@"Person -run"); }
+ (void)eat:(NSString *)food other:(NSString *)other { NSLog(@"Person +eat %@ %@", food, other); }
- (void)eat:(NSString *)food other:(NSString *)other { NSLog(@"Person %zd %@ -eat %@ %@", (long)_age, _name, food, other); }
@end
int sum(int a, int b) { return a + b; }
// swift調(diào)OC
var p = AEPerson(age: 10, name: "Jack" )
p.age = 18
p.name = "Rose"
p.run() // 18 Rose -run
p.eat("Apple", other: "Water") // 18 Rose -eat Apple Water
AEPerson.run() // Person +run
AEPerson.eat("Pizza", other: "Banana") // Person +eat Pizza Banana
print(sum(10, 20)) // 30
Swift調(diào)用OC - @_silgen_name
- 如果C語言暴露給Swift的凾數(shù)名跟Swift中的其他凾數(shù)名沖突了
- 可以在Swift中使用 @_silgen_name 修改C函數(shù)名
// C語言
int sum(int a, int b) {}
return a + b;
}
// Swift
@_silgen_name("sum") func swift_sum(_ v1: Int32, _ v2: Int32) -> Int32
func oc1() {
print(swift_sum(10, 20)) // 30
print(sum(10, 20)) // 30
}
OC調(diào)用Swift
- Xcode已經(jīng)默認(rèn)生成一 個用于OC調(diào)用Swift的頭文件,文件名格式是: {targetName}-Swift.h
■ Swift暴露給OC的類最終繼承自NSObject
■ 使用@objc修飾需要暴露給OC的成員
■ 使用@objcMembers修飾類
口 代表默認(rèn)所有成員都會暴露給OC(包括擴(kuò)展中定義的成員)
口 最終是否成功暴露,還需要考慮成員自身的訪問級別
@objcMembers class Car: NSObject {
var price: Double
var band: String
init(price: Double, band: String) {
self.price = price
self.band = band
}
func run() { print(price, band, "run") }
static func run() { print("Car run") }
}
extension Car {
func test() { print(price, band, "test") }
}
■可以通過@objc重命名Swift暴露給OC的符號名 (類名惫周、屬性名、函數(shù)名等)
@objc(AECar)
@objcMembers class Car: NSObject {
var price: Double
@objc(name)
var band: String
init(price: Double, band: String) {
self.price = price
self.band = band
}
@objc(drive)
func run() { print(price, band, "run") }
static func run() { print("Car run") }
}
extension Car {
@objc(exec:v2:)
func test(name: String, price: Int) { print(price, band, "test") }
}
注:在OC中引入頭文件#import "{targetName}-Swift.h"
AECar *car = [[AECar alloc] initWithPrice:10.5 band:@"Bently"];
car.name = @"BMW";
car.price = 109;
[car drive];
[AECar run];
選擇器 ( Selector )
- Swift中依然可以使用選擇器,使用#selector(name)定義一個選擇器
- 必須是被@objcMembers或@objc修怖的方法オ可以定義選擇器
@objcMembers class Person2: NSObject {
func test1(v1: Int) { print("test1") }
func test2(v1: Int, v2: Int) { print("test2(v1:v2:)") }
func test2(_ v1: Double,_ v2: Double) { print("test2(_ :_ _:)") }
func run() {
perform( #selector(test1))
perform(#selector(test1(v1:)))
perform(#selector(test2(v1:v2:)))
perform(#selector(test2(_:_:)))
perform(#selector(test2 as (Double, Double) -> Void))
}
}
String
■Swift的字符串類型String ,跟OC的NSString ,在API設(shè)計(jì)上還是有較大差異
//空字符串
var emptyStr1 = ""
var emptyStr2 = String()
var str1 = "123456"
print(str1.hasPrefix("123")) // true
print(str1.hasSuffix("456")) // true
var str: String = "1"
// 拼接康栈, jack_rose
str.append("_2")
//重載運(yùn)算符+
str = str + "_3"
//重載運(yùn)算符+=
str += "_4"
// \()插值
str = "\(str)_5"
//長度,9喷橙,1_2_3_4_5
print(str.count)
String的插入和刪除
var str = "1_2"
// 1_2_
str.insert("_", at: str.endIndex)
//1_2_3_4
str.insert(contentsOf: "3_4", at: str.endIndex)
// 1666_2_3_4
str.insert(contentsOf: "666", at: str.index(after: str.startIndex))
// 1666_2_3_8884
str.insert(contentsOf: "888", at: str.index(before: str.endIndex) )
// 1666hello_ 2_ _3_ 8884
str.insert( contentsOf: "hello", at: str.index(str.startIndex, offsetBy: 4))
var str = "1_2"
//1_2_
str.insert("_", at: str.endIndex)
//1_2_3_4
str.insert(contentsOf: "3_4", at: str.endIndex)
// 1666_2_3_ 4
str.insert(contentsOf: "666", at: str.index(after: str.startIndex) )
// 1666_2_3_8884
str.insert(contentsOf: "888", at: str.index(before: str.endIndex))
// 1666hello_2_3_8884
str.insert(contentsOf: "hello", at: str.index(str.startIndex, offsetBy: 4))
// 666hello_2_3_8884
str.remove(at: str.firstIndex(of: "1")!)
// hello_2_3_8884
str.removeAll { $0 == "6" }
var range = str.index(str.endIndex, offsetBy: -4)..<str.index(before: str.endIndex)
// hello_2_3_4
str.removeSubrange(range)
Substring
// String可以通過下標(biāo), prefix啥么、suffix等截取子串,子串類型不是String ,而是Substring
var str="1_2_3_4_5"
// 1_2
var substr1 = str.prefix(3)
//4_5
var substr2 = str.suffix(3)
// 1_2
var range = str.startIndex..<str.index(str.startIndex, offsetBy: 3)
var substr3 = str[range]
// 最初的String, 1_2_3_4_5
print(substr3.base)
// Substring -> String
var str2 = String(substr3)
// ■Substring和它的base ,共享字符串?dāng)?shù)據(jù)
// Substring轉(zhuǎn)為String時, 會重新分配新的內(nèi)存存儲字符串?dāng)?shù)據(jù)
String與Character
for c in "jack" {// c是Character類型
print(c)
}
var str = "jack"
// c是Character類型
var c = str[str.startIndex]
多行String
let str = """
1
"2"
3
'4'
"""
//縮進(jìn)以結(jié)尾的3引號為對齊線
let str9 = """
1
"2"
3
'4'
"""
#warning("要顯示3引號有問題啊")
// 如果要顯示3引號, 至少轉(zhuǎn)義1個引號
let str0 = """
Escaping the first quote \"""
Escaping two quotes \"\""
Escaping all three quotes \"\"\"
"""
//以下2個字符串是等價的
let str1 = "These are the same."
let str2 = """
These are the same.
"""
String 與 NSString
- String 與 NSString之間可以隨時隨地橋接轉(zhuǎn)換
-如果你覺得String的API過于復(fù)雜難用,可以考慮將String轉(zhuǎn)為NSString
var str10: String = "jack"
var str20: NSString = "rose"
var str3 = str1 as NSString
var str4 = str2 as String
// ja
var str5 = str3.substring (with: NSRange(location: 0, length: 2))
print(str5)
- 比較字符串內(nèi)容是否等價
- String使用 == 運(yùn)算符
- NSString使用isEqual方法,也可以使用==返算符(本貭還是調(diào)用了isEqual方法)
Swift贰逾、 OC橋接轉(zhuǎn)換表
Swift | OC | |
---|---|---|
String | ?? | NSString |
String | ?? | NSMutableString |
Array | ?? | NSArray |
Array | ?? | NSMutableArray |
Dictionary | ?? | NSDictionary |
Dictionary | ?? | NSMutableDictionary |
Set | ?? | NSSet |
Set | ?? | NSMutableSet |
只能被class繼承的協(xié)議
protocol Runnable1: AnyObject {}
protocol Runnable2: class {}
@objc protocol Runnable3 {}
- 被@objc修飾的協(xié)議悬荣,還可以暴露給OC取遵守實(shí)現(xiàn)
可選協(xié)議
■可以通過 @objc定義可選協(xié)議,這種協(xié)議只能被class遵守
@objc protocol Runnable {
func run1()
@objc optional func run2()
func run3()
}
class Dog: Runnable {
func run3() { print ("Dog run3") }
func run1() { print("Dog run1") }
}
var d = Dog()
d.run1() // Dog run1
d.run3() // Dog run3
dynamic
■被 @objc dynamic 修怖的內(nèi)容會具有劫恣性,比如凋用方法會走runtime那一套流程
class Dog: NSObject {
@objc dynamic func test1() {}
func test2() {}
}
var d = Dog()
d.test1()
d.test2()
KVC\KVO
■Swift支持KVC\KVO的條件
- 屬性所在的類、監(jiān)聽器最終繼承自NSObject
- 用 @objc dynamic 修飾對應(yīng)的屬性
class Observer: NSObject {
override func observeValue(forKeyPath keyPath: String?,
of object: Any?,
change: [NSKeyValueChangeKey : Any]?,
context: UnsafeMutableRawPointer?) {
print ("observeValue", change?[.newKey] as Any)
}
}
class Person: NSObject {
@objc dynamic var age: Int = 0
var observer: Observer = Observer()
override init() {
super.init( )
self.addObserver(observer,
forKeyPath: "age",
options: .new,
context: nil)
}
deinit {
self.removeObserver(observer,
forKeyPath: "age")
}
}
var p = Person( )
// observeValue Optional(20)
p.age = 20
// observeValue Optional(25)
p.setValue(25, forKey: "age")
block方式的KVO
class Person: NSObject {
@objc dynamic var age: Int = 0
var observation: NSKeyValueObservation?
override init() {
super.init( )
observation = observe(\Person.age, options: .new, changeHandler: { (person, change) in
print(change.newValue as Any)
})
}
}
var p = Person( )
// Optional(20)
p.age = 20
// Optional(25)
p.setValue(25, forKey: "age")
關(guān)聯(lián)對象( Associated Object )
//在Swift中, class依然可以使用關(guān)聯(lián)對象
- 默認(rèn)情況, extension不可以增加存儲屬性
- 借助關(guān)聯(lián)對象,可以實(shí)現(xiàn)類似extension為class增加存儲屬性的效果
class Person {}
extension Person {
private static var AGE_KEY: Void?
var age: Int {
get {
(objc_getAssociatedObject(self, &Self.AGE_KEY) as? Int) ?? 0
}
set {
objc_setAssociatedObject(self, &Self.AGE_KEY, newValue, .OBJC_ASSOCIATION_ASSIGN)
}
}
}
資源名管理
enum R {
enum string: String {
case add = "添加"
}
enum image: String {
case logo
}
enum segue: String {
case login_main
}
}
func testR() {
let img = UIImage(named: "logo")
let btn = UIButton(type: .custom)
btn.setTitle("添加", for: .normal)
performSegue(withIdentifier: "login_main", sender: self)
let img = UIImage (R.image.logo)
let btn = UIButton(type: .custom)
btn.setTitle(R.string.add, for: .normal)
performSegue ( withIdentifier: R.segue. login_main, sender: self)
}
//or
extension UIImage {
convenience init?(_ name :R.image) {
self.init(named: name.rawValue)
}
}
extension UIViewController {
func performSegue(withIdentifier identifier: R.segue, sender: Any?) {
performSegue(withIdentifier: identifier .rawValue, sender: sender)
}
}
extension UIButton {
func setTitle(_ title: R.string, for state: UIControl.State) {
setTitle(title.rawValue, for: state)
}
}
■這種做法實(shí)際上是參考了Android的資源名管理方式
資源名管理的其他思路
let img = UIImage(named: "logo")
let font = UIFont(name: "Arial", size: 14)
let img = R.image.logo
let font = R.font.arial(14)
enum R {
enum image {
static var logo = UIImage (named: "logo")
}
enum font {
static func arial(_ size: CGFloat) -> UIFont? {
UIFont(name: "Arial", size: size)
}
}
}
多線程開發(fā)
異步
public typealias Task = () -> Void
struct Queue {
public static func async(_ task: @escaping Task) {
_async(task)
}
public static func async(_ task: @escaping Task,
mainTask: @escaping Task) {
_async(task, mainTask)
}
private static func _async(_ task: @escaping Task,
_ mainTask: Task? = nil) {
let item = DispatchWorkItem( block: task)
DispatchQueue.global().async(execute: item)
if let main = mainTask {
item.notify(queue: DispatchQueue.main, execute: main)
}
}
}
延遲
@discardableResult
public static func delay(_ seconds: Double, _ block: @escaping Task) -> DispatchWorkItem {
let item = DispatchWorkItem(block: block)
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + seconds, execute: item)
return item
}
異步延遲
@discardableResult
public static func asyncDelay(_ seconds: Double ,
_ task: @escaping Task) -> DispatchWorkItem {
return _asyncDelay(seconds, task)
}
@discardableResult
public static func asyncDelay(_ seconds: Double,
_ task: @escaping Task,
_ mainTask: @escaping Task) -> DispatchWorkItem {
return _asyncDelay(seconds, task, mainTask)
}
private static func _asyncDelay(_ seconds: Double,
_ task: @escaping Task,
_ mainTask: Task? = nil) -> DispatchWorkItem {
let item = DispatchWorkItem(block: task)
DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + seconds,
execute: item)
if let main = mainTask {
item.notify(queue: DispatchQueue.main, execute: main)
}
return item
}
once
■ dispatch_once在Swift中已被廢棄,取而代之
- 可以用類型屬性或者全局變量\常量
- 默認(rèn)自帶lazy + dispatch_once效果
let age1: Int = {
print( 666)
return 10
}()
class ViewController: UIViewController {
static let age2: Int = {
print (888)
return 20
}()
override func viewDidLoad() {
super.viewDidLoad()
print (age1)
print(age1)
// 666 10 10
print (ViewController.age2)
print (ViewController.age2)
// 888 20 20
}
}
加鎖
//gcd信號量
class Cache {
private static var data = [String: Any]()
private static var lock = DispatchSemaphore(value: 1)
static func set(_ key: String, value: Any) {
lock.wait()
defer { lock.signal() }
data [key] = value
}
}
//Foundation
private static var lock = NSLock()
static func set(_ key: String,_ value: Any) {
lock.lock()
defer { lock.unlock() }
}
private static var lock = NSRecursiveLock()
static func set(_ key: String,_ value: Any) {
lock.lock()
defer { lock.unlock() }
}