訪問控制
在訪問權(quán)限控制這塊褂删,Swift提供了5個(gè)不同的訪問級別,以下是從高到低的敘述冲茸,其中
實(shí)體是指被訪問級別修飾的內(nèi)容
屯阀;open
:允許在定義實(shí)體的模塊缅帘,其他模塊中訪問,允許其他模塊進(jìn)行繼承难衰,重寫股毫,open
只能用在類class,類成員上召衔,不允許用在枚舉與結(jié)構(gòu)體上铃诬,這里的模塊是指工程編譯生成的Mach-O可執(zhí)行文件
;-
public
:允許在定義實(shí)體的模塊苍凛,其他模塊中訪問趣席,不允許其他模塊進(jìn)行繼承,重寫醇蝴,這里的模塊同上宣肚;
-
internal
:只允許在定義實(shí)體的模塊中訪問,不允許其他模塊訪問悠栓,這里的模塊是指子模塊
霉涨,如下圖所示:
fileprivate
:只允許在定義實(shí)體的源文件
中訪問,即在指定的.swift文件中訪問惭适,在其他.swift文件中不能訪問笙瑟;private
:只允許在定義實(shí)體的封閉聲明
中訪問,例如在一個(gè).swift文件中定義A癞志,B兩個(gè)Class類往枷,那么A類中定義的實(shí)體只能在A類中訪問,不能在B類中訪問凄杯;絕大部分實(shí)體默認(rèn)都是
internal
級別错洁;
訪問級別的使用準(zhǔn)則
- 一個(gè)實(shí)體不可以被更低訪問級別的實(shí)體定義;
- 變量類型的訪問級別
大于等于
變量的訪問級別戒突; - 參數(shù)類型/返回值類型的訪問級別
大于等于
函數(shù)的訪問級別屯碴; - 父類的訪問級別
大于等于
子類的訪問級別; - 父協(xié)議的訪問級別
大于等于
子協(xié)議的訪問級別膊存; - 原類型的訪問級別
大于等于
typealias的訪問級別; - 原始值导而,關(guān)聯(lián)值類型的訪問級別
大于等于
枚舉的訪問級別; - 定義類型A所用到的其他類型的訪問級別
大于等于
A的訪問級別膝舅;
- 變量類型的訪問級別
元組類型
- 元組類型的訪問級別是其所有成員類型最低的那個(gè)嗡载;
internal struct Dog { }
fileprivate class Person { }
fileprivate var data1: (Dog,Person)
private var data2: (Dog,Person)
var data3: (Dog,Person) //報(bào)錯(cuò)
-
(Dog,Person)
是元組類型,其中Dog的訪問級別> Person的訪問級別仍稀,所以(Dog,Person)元組的訪問級別為fileprivate
- 現(xiàn)在用元組類型來定義變量,那么元組類型的訪問級別必須
大于等于變量data1埂息,data2技潘,data3的訪問級別遥巴,data3默認(rèn)的訪問級別為internal
,所以報(bào)錯(cuò)享幽;
泛型
- 泛型類型的訪問級別是
類型的訪問級別
以及所有泛型類型參數(shù)的訪問級別
中最低的那個(gè)铲掐;
internal class Car { }
fileprivate class Dog {}
public class Person<T1, T2> { }
fileprivate var p = Person<Car,Dog>()
-
< >
中的內(nèi)容表示泛型,其訪問級別是Person值桩,Car摆霉,Dog這三個(gè)訪問級別中最低的那個(gè),所以泛型的訪問級別為fileprivate奔坟;
成員携栋,嵌套類型
- 類型的訪問級別會(huì)影響成員(方法,屬性咳秉,下標(biāo)婉支,初始化器),嵌套類型的默認(rèn)訪問級別澜建;
- 一般情況下向挖,類型為
private
或fileprivate
,那么成員炕舵,嵌套類型默認(rèn)也為private
或fileprivate
- 一般情況下何之,類型為
internal
或public
,那么成員咽筋,嵌套類型默認(rèn)是internal
帝美,
fileprivate class Person {
var age = 0
func run() { }
enum Season {
case spring,summer,autum,winter
}
}
- 類型為
fileprivate
,那么其所有成員晤硕,也為fileprivate
public class Person {
var age = 0
func run() { }
enum Season {
case spring,summer,autum,winter
}
}
- 類型為
public
悼潭,其所有成員為internal
在main.swift文件中直接定義 代碼如下:
import Foundation
private class Person { }
fileprivate class Student : Person { }
- 根據(jù)上面的規(guī)則,父類的訪問級別要大于等于子類的訪問級別舞箍,按理說會(huì)報(bào)錯(cuò)舰褪,但編譯成功,原因在于
Person
與Student
疏橄,是在main.swift源文件的直接定義的占拍,在整個(gè)main.swift源文件中都可以訪問,如果做如下改動(dòng):
import Foundation
class TestClass {
private class Person { }
fileprivate class Student : Person { }
}
- 就會(huì)報(bào)錯(cuò)捎迫,因?yàn)镻erson的作用域僅局限于TestClass的內(nèi)部晃酒,Student是在整個(gè)main.swift源文件中都可以訪問,若在main.swift源文件中直接實(shí)例Student窄绒,就不能訪問其父類Person贝次,所以會(huì)報(bào)錯(cuò);
class Test {
private struct Dog {
var age: Int = 0
func run(){}
}
private struct Person {
var dog: Dog = Dog()
mutating func walk() {
dog.run()
dog.age = 1
}
}
}
- 編譯通過彰导,根據(jù)上面的規(guī)則蛔翅,private struct Dog 敲茄,那么其成員age與run的訪問級別也為private,然而dog.run山析,依然能在Person內(nèi)部使用堰燎,原因在于成員age與run的訪問級別的private是與類Dog的private的作用域是一致的,若改成下面的:
class Test {
private struct Dog {
private var age: Int = 0
private func run(){}
}
private struct Person {
var dog: Dog = Dog()
mutating func walk() {
dog.run()
dog.age = 1
}
}
}
- 編譯報(bào)錯(cuò)笋轨,private func run(){}秆剪,不能在Person中使用;
成員的重寫
- 子類重寫成員的訪問級別必須 >= 子類的訪問級別 或者 >= 父類被重寫成員的訪問級別爵政;
public class Person {
fileprivate func run() {
}
}
public class Student : Person {
fileprivate override func run() {
}
}
getter仅讽,setter
- getter,setter默認(rèn)自動(dòng)接收它們所屬環(huán)境的訪問級別茂卦;
- 可以給setter單獨(dú)設(shè)置一個(gè)比getter更低的訪問級別何什,用以限制寫的權(quán)限;
class Person {
private(set) var age: Int = 0
fileprivate(set) public var weight: Int {
set {
}
get {
10
}
}
internal(set) public subscript(index: Int) -> Int {
set {
}
get {
index
}
}
}
var p: Person = Person()
p.age = 10 //不能寫等龙,報(bào)錯(cuò)
print(p.age)
初始化器
- 如果一個(gè)
public
類想在另一個(gè)模塊調(diào)用編譯生成的默認(rèn)無參初始化器处渣,必須顯示提供public
的無參初始化器, 因?yàn)?code>public類的默認(rèn)初始化器是internal
級別蛛砰; -
required
初始化器 >= 它的默認(rèn)訪問級別
class Person {
fileprivate required init() {}
}
會(huì)報(bào)錯(cuò)罐栈,因?yàn)?code>class Person的默認(rèn)訪問級別為
internal
,根據(jù)上面的規(guī)則:required
初始化器 >= 它的默認(rèn)訪問級別泥畅,而現(xiàn)在required初始化器的訪問級別為fileprivate
<internal
荠诬,所以報(bào)錯(cuò);如果結(jié)構(gòu)體有
private/fileprivate
的存儲(chǔ)屬性位仁,那么它的成員初始化器也是private/fileprivate
柑贞,默認(rèn)為internal
struct Point {
fileprivate var x = 0
var y = 0
}
var p: Point = Point(x: 10, y: 20)
枚舉類型的case
- 不能給enum的每個(gè)case設(shè)置訪問級別;
- 每個(gè)case自動(dòng)接收enum的訪問級別聂抢;
public enum Season {
case spring,summer,autum,winter
}
- enum是public
- 所有的case也都是public
協(xié)議
- 協(xié)議中定義的要求自動(dòng)接收協(xié)議的訪問級別钧嘶,不能單獨(dú)設(shè)置訪問級別,跟枚舉類似琳疏;
- 協(xié)議實(shí)現(xiàn)的訪問級別 >= 類型的訪問級別 或者 >= 協(xié)議的訪問級別
//協(xié)議的訪問級別public
public protocol Runnable {
func run()
}
//類型的訪問級別fileprivate
fileprivate class Person : Runnable{
//協(xié)議實(shí)現(xiàn)的訪問級別internal
internal func run() {
}
}
擴(kuò)展
- 如果有顯示設(shè)置擴(kuò)展的訪問級別有决,擴(kuò)展添加的成員自動(dòng)接收擴(kuò)展的訪問級別;
- 如果沒有顯示設(shè)置擴(kuò)展的訪問級別空盼,擴(kuò)展添加的成員的默認(rèn)訪問級別與直接在類型中定義的成員一樣书幕;
- 可單獨(dú)給擴(kuò)展的成員設(shè)置訪問級別;
- 不能給用于遵守協(xié)議的擴(kuò)展顯示設(shè)置擴(kuò)展的訪問級別揽趾;
protocol Runnable {
func run()
}
class Person{
}
fileprivate extension Person : Runnable { //報(bào)錯(cuò)
}
- 在同一文件中的擴(kuò)展台汇,可以寫成類似多個(gè)部分的類型聲明;
- 在原本的聲明中定義一個(gè)私有成員,可以在同一文件的擴(kuò)展中訪問它励七;
- 在擴(kuò)展中定義一個(gè)私有成員智袭,可以在同一文件的其他擴(kuò)展中奔缠,原本聲明中訪問它尉桩;
public class Person {
private func run0() {}
private func eat0() {
run1()
}
}
extension Person {
private func run1() {}
private func eat1() {
run0()
}
}
extension Person {
private func eat2() {
run1()
}
}
將方法賦值給let或者var
struct Person {
var age: Int
func run(_ v: Int) {
print("run",age,v)
}
static func run(_ v: Int) {
print("static run",v)
}
}
var fn1 = Person.run
fn1(20)
var fn2: (Person) -> (Int) -> () = Person.run
fn2(Person(age: 10))(20)
struct Person {
var age: Int
func run(_ v: Int) {
print("run",age,v)
}
static func run(_ v: Int) {
print("static run",v)
}
}
//(Person) -> (Int) -> ()
var fn = Person.run
//fn1是帶有Person實(shí)例的run方法
//(Int) -> ()
var fn1 = fn(Person(age: 10))
//最后傳入?yún)?shù)20珊豹,調(diào)用run方法
fn1(20)
內(nèi)存管理
- 與OC一樣,Swift也是采取基于引用計(jì)數(shù)的ARC內(nèi)存管理方案;
- Swift的ARC中有3種引用:
- 強(qiáng)引用:默認(rèn)情況下伍绳,都是強(qiáng)引用;
- 弱引用:通過
weak
來定義弱引用站楚,必須是可選類型的var蝠引,因?yàn)閷?shí)例銷毀后,ARC會(huì)自動(dòng)將若引用置為nil抱怔;ARC自動(dòng)給弱引用設(shè)置為nil時(shí)劣坊,是不會(huì)觸發(fā)屬性觀察器的;
- 無主引用(unowned reference):通過
unowned
定義無主引用屈留,其不會(huì)產(chǎn)生強(qiáng)引用局冰,實(shí)例對象銷毀之后引用依然指向?qū)嵗膬?nèi)存地址,類似于OC中的unsafe_unretained
灌危,試圖在實(shí)例對象銷毀后康二,訪問無主引用,會(huì)導(dǎo)致野指針錯(cuò)誤勇蝙; -
weak
與unowned
只能應(yīng)用于類的實(shí)例上面沫勿;
protocol Liveable : AnyObject {
}
class Person {
}
weak var p0: Person?
weak var p1: AnyObject?
weak var p2: Liveable?
unowned var p3: Person?
unowned var p4: AnyObject?
unowned var p5: Liveable?
AutoRelease
循環(huán)引用
-
weak
與unowned
都能解決循環(huán)引用的問題,但unowned
要比weak
少一些性能消耗味混; - 在實(shí)例對象的生命周期中會(huì)變成nil的产雹,使用
weak
- 實(shí)例對象初始化賦值之后,再也不會(huì)變成nil的翁锡,使用
unowned
閉包的循環(huán)引用
- 閉包表達(dá)式默認(rèn)會(huì)對用到的外層對象產(chǎn)生額外的強(qiáng)引用(即對外層對象進(jìn)行了retain操作)
class Person {
var fn: (() -> ())?
func run() {
print("Person run")
}
deinit {
print("Person deinit")
}
}
func test() {
let p: Person = Person()
p.fn = {
p.run()
}
}
test()
- 閉包fn蔓挖,會(huì)對p進(jìn)行強(qiáng)引用,導(dǎo)致p無法被釋放盗誊,造成內(nèi)存泄漏时甚;
- 解決方案:在閉包表達(dá)式的捕獲列表聲明
weak
或unowned
引用,解決循環(huán)引用問題哈踱;
class Person {
var fn: (() -> ())?
func run() {
print("Person run")
}
deinit {
print("Person deinit")
}
}
func test() {
let p: Person = Person()
p.fn = {
[weak p] in
p?.run()
}
}
test()
- 或者
class Person {
var fn: (() -> ())?
func run() {
print("Person run")
}
deinit {
print("Person deinit")
}
}
func test() {
let p: Person = Person()
p.fn = {
[unowned p] in
p.run()
}
}
test()
- 或者
class Person {
var fn: (() -> ())?
func run() {
print("Person run")
}
deinit {
print("Person deinit")
}
}
func test() {
let p: Person = Person()
p.fn = {
[weak wp = p] in
wp?.run()
}
}
test()
- 先看一個(gè)實(shí)例代碼:
class Person {
lazy var fn: (() -> ()) = {
[weak weakSelf = self] in
weakSelf?.run()
}
func run() {
print("Person run")
}
deinit {
print("Person deinit")
}
}
func test() {
var p: Person = Person()
p.fn()
}
test()
- 上述閉包內(nèi)部用到實(shí)例的成員荒适,必須強(qiáng)制寫上self,否則會(huì)報(bào)錯(cuò)开镣,因?yàn)檫@樣可以提醒開發(fā)者刀诬,可能會(huì)造成循環(huán)引用;
-
lazy var fn: (() -> ()) = { }
邪财,只有使用到fn陕壹,才會(huì)去初始化加載fn质欲,也就是說調(diào)用p.fn()
,才會(huì)初始化fn糠馆,可能會(huì)造成循環(huán)引用嘶伟; - 再看一段代碼:
class Person {
var age: Int = 0
lazy var getAge: Int = {
self.age
}()
deinit {
print("Person deinit")
}
}
func test() {
var p: Person = Person()
print(p.getAge)
}
test()
- 如果將
lazy
刪除,self.age
會(huì)報(bào)錯(cuò)又碌,這是因?yàn)閟elf實(shí)例還沒初始化九昧,就調(diào)用getAge
,若加上lazy
毕匀,只有當(dāng)實(shí)例初始化后才去調(diào)用getAge
铸鹰,就不會(huì)報(bào)錯(cuò)了; - 如果lazy屬性是閉包調(diào)用的結(jié)果皂岔,那么就不用考慮循環(huán)引用問題蹋笼,因?yàn)殚]包調(diào)用后,閉包的生命周期就結(jié)束了躁垛;
@escaping
- 非逃逸閉包剖毯,逃逸閉包,一般都是當(dāng)作參數(shù)傳遞給函數(shù)缤苫;
- 非逃逸閉包:閉包調(diào)用發(fā)生在函數(shù)結(jié)束之前速兔,閉包作用域在函數(shù)之內(nèi);
func test(_ fn: () -> ()) {
fn()
}
test {
print("1111")
}
-
fn
是非逃逸閉包活玲,其調(diào)用在test函數(shù)內(nèi)部涣狗; - 逃逸閉包:閉包有可能在函數(shù)結(jié)束后調(diào)用,閉包調(diào)用逃離了函數(shù)的作用域舒憾,需要通過
@escaping
進(jìn)行聲明镀钓;
import Dispatch
typealias Fn = () -> ()
var gFn: Fn?
func test1(_ fn: @escaping Fn) {
gFn = fn
}
func test2(_ fn: @escaping Fn) {
DispatchQueue.global().async {
fn()
}
}
-
fn
是逃逸閉包,其調(diào)用不在test1镀迂,test2的函數(shù)內(nèi)部丁溅; - 逃逸閉包是不能捕獲inout類型的參數(shù)的,因?yàn)樘右蓍]包的調(diào)用是不確定的探遵,而inout類型的參數(shù)是傳入變量的內(nèi)存地址給逃逸閉包窟赏,有可能變量已經(jīng)銷毀了,逃逸閉包再去修改變量所指向的內(nèi)存箱季;
局部作用域
- 在Swift中用
do { }
定義局部作用域涯穷;
class Dog {
var age: Int = 10
func run() {
}
}
do {
let dog1: Dog = Dog()
dog1.age = 20
}
do {
let dog2: Dog = Dog()
dog2.age = 20
}
- dog1在第一個(gè)do{}作用域內(nèi),dog2在第二個(gè)do{}作用域內(nèi)藏雏,超出作用域拷况,就會(huì)被釋放回收;
內(nèi)存訪問沖突
- 既然是內(nèi)存訪問沖突,說明至少有兩個(gè)訪問赚瘦,訪問同一資源粟誓;
- 內(nèi)存訪問沖突的發(fā)生條件:
- 兩個(gè)訪問,至少有一個(gè)寫入操作起意;
- 兩個(gè)訪問鹰服,訪問的是同一塊內(nèi)存;
- 兩個(gè)訪問的訪問時(shí)間重疊(比如在同一個(gè)函數(shù)內(nèi))
- 看下面一段代碼:
var step = 1
func increment(_ num: inout Int) {
num += step
}
increment(&step)
- 報(bào)錯(cuò):
Simultaneous accesses to 0x100008020, but modification requires exclusive access
-
num += step
即讀取杜恰,寫入同一塊內(nèi)存获诈,且訪問時(shí)間重疊仍源,造成內(nèi)存訪問沖突心褐,解決方案如下:
var step = 1
func increment(_ num: inout Int) {
num += step
}
var copyStep = step
increment(©Step)
step = copyStep
- 再看一段代碼:
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) //OK
balance(&num1, &num1) //Error
balance(&num1, &num1)
會(huì)報(bào)錯(cuò),因?yàn)閭鲄⒍际莕um1的內(nèi)存地址笼踩,當(dāng)執(zhí)行y = sum - x
就會(huì)出現(xiàn)內(nèi)存訪問沖突逗爹;那么若傳入一個(gè)結(jié)構(gòu)體的兩個(gè)不同成員,給balance函數(shù)嚎于,肯定會(huì)報(bào)錯(cuò)的掘而,因?yàn)榻Y(jié)構(gòu)體成員都是存儲(chǔ)在結(jié)構(gòu)體中的,是同一塊內(nèi)存于购,所以會(huì)造成內(nèi)存訪問沖突袍睡;
若滿足下面的條件,就說明重疊訪問結(jié)構(gòu)體的成員是安全的:
只訪問實(shí)例存儲(chǔ)屬性肋僧,不是計(jì)算屬性或類屬性斑胜;
結(jié)構(gòu)體是局部變量不是全局變量;
結(jié)構(gòu)體沒有被閉包捕獲 或者 只被非逃逸閉包捕獲嫌吠;
指針
- 在Swift中有專門的指針類型止潘,這些都被定性為不安全的,常見的有以下四種類型:
- UnsafePointer<Pointee> 類似于const Pointee *
- UnsafeMutablePointer<Pointee> 類似于Pointee *
- UnsafeRawPointer<Pointee> 類似于const void *
- UnsafeMutableRawPointer<Pointee> 類似于 void *
- 其中<Pointee>表示泛型辫诅,Mutable表示可修改凭戴;
var age = 10
func test1(_ ptr: UnsafeMutablePointer<Int>) {
//修改地址中的值
ptr.pointee = 20
print("test1",ptr.pointee)
}
func test2(_ ptr: UnsafePointer<Int>) {
//訪問地址中的值
print("test2",ptr.pointee)
}
test1(&age)
test2(&age)
print(age) //20
var age = 10
func test3(_ ptr: UnsafeRawPointer) {
print("test3",ptr.load(as: Int.self))
}
func test4(_ ptr: UnsafeMutableRawPointer) {
ptr.storeBytes(of: 30, as: Int.self)
}
test3(&age)//10
test4(&age)
print(age)//30
- 由于UnsafeRawPointer是任意類型的指針,所以從它內(nèi)存中取數(shù)據(jù)時(shí)炕矮,必須指定數(shù)據(jù)類型么夫,它才知道取多少字節(jié)的數(shù)據(jù),所以必須傳入數(shù)據(jù)類型參數(shù)肤视;
指針的應(yīng)用實(shí)例
var arr = NSArray(objects: 11,22,33,44)
print(arr)
//UnsafeMutablePointer<ObjCBool> stop
arr.enumerateObjects { (element, idx, stop) in
print(idx,element)
//idx = 2時(shí)档痪,停止遍歷
if idx == 2 {
stop.pointee = true
}
}
-
stop
是UnsafeMutablePointer<ObjCBool> 指針類型;
獲取指向某個(gè)變量的指針
//age的地址值為:0x100008188
var age = 10
//UnsafePointer<Int> 類型
//ptr的值為:0x100008188
var ptr1 = withUnsafePointer(to: &age) { $0 }
print(ptr1.pointee)
var ptr3 = withUnsafePointer(to: &age) { (p) -> UnsafePointer<Int> in
return p
}
//UnsafeMutableRawBufferPointer
var ptr2 = withUnsafeMutablePointer(to: &age) { $0 }
ptr2.pointee = 20
print(age)
var ptr4 = withUnsafeMutablePointer(to: &age) { UnsafeMutableRawPointer($0) }
ptr4.storeBytes(of: 40, as: Int.self)
var ptr5 = withUnsafePointer(to: &age) { UnsafeRawPointer($0)}
print(ptr5.load(as: Int.self)) //40
- 獲取變量a的引用指針钢颂;
- 其中ptr1余ptr2是等價(jià)寫法钞它;
獲取指向堆空間的指針
class Person {
}
//person是堆空間的地址值 即實(shí)例對象的地址值
var person: Person = Person()
//personPtr是全局區(qū)的地址值,也就是引用變量的地址值
var personPtr = withUnsafePointer(to: &person) { $0 }
print(personPtr)
print("1111")
class Person {
}
//person是指針變量 其值是堆空間的地址值
var person: Person = Person()
//personPtr是全局區(qū)的地址值,也就是引用指針變量person的地址值
var personPtr = withUnsafePointer(to: &person) { UnsafeRawPointer($0) }
print(personPtr)
//address是person對象堆空間的地址值
var address = personPtr.load(as: UInt.self)
//ptr2是指向address堆空間的指針變量
var ptr2 = UnsafeMutableRawPointer(bitPattern: address)
print(ptr2)
print("1111")
-
var ptr2 = UnsafeMutableRawPointer(bitPattern: address)
遭垛,根據(jù)堆空間獲取一個(gè)指向堆空間的指針變量尼桶;
創(chuàng)建指針
//申請堆空間
var ptr = malloc(16)
//存 前8個(gè)字節(jié)
ptr?.storeBytes(of: 10, as: Int.self)
//存 后8個(gè)字節(jié)
ptr?.storeBytes(of: 20, toByteOffset: 8, as: Int.self)
//取 前8個(gè)字節(jié)
print((ptr?.load(as: Int.self))!) //10
//取 后8個(gè)字節(jié)
print((ptr?.load(fromByteOffset: 8, as: Int.self))!) //20
//銷毀堆內(nèi)存空間
free(ptr)
//另一種寫法 -----------------------------------------------------
//申請堆空間
var ptr = UnsafeMutableRawPointer.allocate(byteCount: 16, alignment: 1)
//存 前8個(gè)字節(jié)
ptr.storeBytes(of: 10, as: Int.self)
//存 后8個(gè)字節(jié)
ptr.advanced(by: 8).storeBytes(of: 20, as: Int.self)
//取 前8個(gè)字節(jié)
print(ptr.load(as: Int.self)) //10
//取 后8個(gè)字節(jié)
print(ptr.advanced(by: 8).load(as: Int.self)) //20
//銷毀堆內(nèi)存空間
ptr.deallocate()
//另一種寫法 -----------------------------------------------------
//申請堆空間 8 * 2 = 16個(gè)字節(jié)
var ptr = UnsafeMutablePointer<Int>.allocate(capacity: 2)
//存 前8個(gè)字節(jié)
ptr.initialize(to: 10)
//存 后8個(gè)字節(jié)
ptr.successor().initialize(to: 20)
//取 前8個(gè)字節(jié)
print(ptr.pointee) //10
//取 后8個(gè)字節(jié)
print((ptr+1).pointee) //20
print(ptr[1]) //20
print(ptr.successor().pointee) //20
//銷毀堆內(nèi)存空間
ptr.deinitialize(count: 2)
ptr.deallocate()
class Person {
var age: Int
var name: String
init(age: Int,name: String) {
self.age = age
self.name = name
}
deinit {
print("Person deinit")
}
}
var ptr = UnsafeMutablePointer<Person>.allocate(capacity: 3)
ptr.initialize(to: Person(age: 10, name: "li"))
(ptr+1).initialize(to: Person(age: 20, name: "liyan"))
(ptr+2).initialize(to: Person(age: 30, name: "liyanyan"))
ptr.deinitialize(count: 3)
ptr.deallocate()
指針之間的轉(zhuǎn)換
//任意類型指針
var ptr = UnsafeMutableRawPointer.allocate(byteCount: 16, alignment: 1)
//轉(zhuǎn)成int類型指針
var ptr2 = ptr.assumingMemoryBound(to: Int.self)
ptr.assumingMemoryBound(to: Int.self).pointee = 11
(ptr+8).assumingMemoryBound(to: Double.self).pointee = 22.0
//ptr.deallocate()
var ptr = UnsafeMutableRawPointer.allocate(byteCount: 16, alignment: 1)
ptr.assumingMemoryBound(to: Int.self).pointee = 11
(ptr+8).assumingMemoryBound(to: Double.self).pointee = 22.0
//var ptr2 = unsafeBitCast(ptr, to: UnsafeMutablePointer<Int>.self)
print(unsafeBitCast(ptr, to: UnsafeMutablePointer<Int>.self).pointee)//11
print(unsafeBitCast(ptr, to: UnsafeMutablePointer<Double>.self).pointee)//22.0
ptr.deallocate()
-
unsafeBitCast
忽略數(shù)據(jù)類型的強(qiáng)制轉(zhuǎn)換,不會(huì)因?yàn)閿?shù)據(jù)類型的變化而改變原來的內(nèi)存數(shù)據(jù)锯仪;
class Person {
}
var person = Person()
//personObjectAddress存放的就是person的堆空間地址值
var personObjectAddress = unsafeBitCast(person, to: UnsafeRawPointer.self)
print(personObjectAddress)