十八、内存访问冲突、指针

2020-02-12  本文已影响0人  爱玩游戏的iOS菜鸟

内存访问冲突(Conflicting Access to Memory)

产生内存访问冲突的条件

内存访问冲突会在两个访问满足下列条件时发生:(3个条件同时满足)

  1. 至少一个是写入操作
  2. 它们访问的是同一块内存
  3. 它们的访问时间重叠(比如同一个函数内)
//不存在内存访问冲突
func plus(_ num: inout Int) -> Int{
    num += 1
    return num
}
var num = 1
print(plus(&num))

//存在内存访问冲突
var step = 1
func increment(_ num :inout Int){
    num += step//同时访问和修改 访问冲突
    //Simultaneous accesses to 0x100006668, but modification requires exclusive access.
}

increment(&step)

//存在内存访问冲突
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

//存在内存访问冲突
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: 5)
Oscar.shareHealth(with: &maria)//OK
Oscar.shareHealth(with: &Oscar)//Error

//结构体访问冲突
var tulpe = (health: 10, energy: 20)
balance(&tulpe.health, &tulpe.energy)//Error

var holly = Player(name: "holly", health: 10, energy: 20)
balance(&holly.health, &holly.energy)//Error
不会内存访问冲突的情况

如果下面的条件可以满足,就说明重叠访问结构体的属性是安全的

func test(){
    var tulpe = (health: 10, energy: 20)
    balance(&tulpe.health, &tulpe.energy)//Error
    
    var holly = Player(name: "holly", health: 10, energy: 20)
    balance(&holly.health, &holly.energy)
}

指针

Swift也有专门的指针类型,这些都被定性为"Unsafe",常见的有一下4种类型:

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 age2 = 20
func test3(_ ptr:UnsafeMutableRawPointer){
    ptr.storeBytes(of: 20, as: Int.self)
}

func test4(_ ptr:UnsafeRawPointer){
    print(ptr.load(as: Int.self))
}

test3(&age2)
test4(&age2)//20
print(age)//20
指针的应用示例
var arr = NSArray(objects: 11,22,33,44)

arr.enumerateObjects { (obj, idx, stop) in
    print(idx,obj)
    if idx == 2 {//下标为2就停止遍历
        stop.pointee = true
    }
}

for (idx,obj) in arr.enumerated(){
    print(idx , obj)
    if idx == 2 {
        break
    }
}
  1. 获得指向某个变量的指针
var age = 11

var prt1 = withUnsafeMutablePointer(to: &age) { $0 }

var prt2 = withUnsafePointer(to: &age) { $0 }

prt1.pointee = 22
print(prt2.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))
print(age)
  1. 获得指向堆空间实例的指针
class Person { }
var person = Person()
var ptr = withUnsafePointer(to: &person) { UnsafeRawPointer($0) }
var heapPtr = UnsafeRawPointer(bitPattern: ptr.load(as: UInt.self))
print(heapPtr!)
  1. 创建指针
var ptr = UnsafeRawPointer(bitPattern: 0x100001234)
//创建
var ptr1 = malloc(16)//分配16个字节的堆空间 
//存
ptr1?.storeBytes(of: 11, as: Int.self)//11只占8个字节 所以只初始化前8个字节
ptr1?.storeBytes(of: 22, toByteOffset: 8, as: Int.self)//初始化 后8个字节
//取
print((ptr1?.load(as: Int.self))!)//11 取前8个字节
print((ptr1?.load(fromByteOffset: 8, as: Int.self))!)//22 取后8个字节
//销毁
free(ptr1)

var ptr = UnsafeMutableRawPointer.allocate(byteCount: 16, alignment: 1)
ptr.storeBytes(of: 11, as: Int.self)// 初始化前8个字节 
ptr.advanced(by: 8).storeBytes(of: 22, as: Int.self)//初始化 后8个字节

print(ptr.load(as: Int.self))//11 取前8个字节
print(ptr.advanced(by: 8).load(as: Int.self))//22 取后8个字节
ptr.deallocate()//销毁
//Int类型已确定
var ptr = UnsafeMutablePointer<Int>.allocate(capacity: 3)//3 * 8 24个字节
ptr.initialize(to: 11)
ptr.successor().initialize(to: 22)//后进指向的内存地址赋值 下一个Int空间
ptr.successor().successor().initialize(to: 33)

print(ptr.pointee)//11
print((ptr + 1).pointee)//22
print((ptr + 2).pointee)//33

print(ptr[0])//11
print(ptr[1])//22
print(ptr[2])//33

ptr.deinitialize(count: 3)
ptr.deallocate()
class Person{
    var age: Int
    var name: String
    init(age: Int, name: String) {
        self.age = age
        self.name = name
    }
    deinit {
        print(name,"deinit")
    }
}

var ptr = UnsafeMutablePointer<Person>.allocate(capacity: 3)
ptr.initialize(to: Person(age: 10, name: "Jack"))
(ptr + 1).initialize(to: Person(age: 10, name: "Rose"))
(ptr + 2).initialize(to: Person(age: 10, name: "Kate"))
ptr.deinitialize(count: 3)
ptr.deallocate()
//Jack deinit
//Rose deinit
//Kate deinit
  1. 指针之间的转换
var ptr = UnsafeMutableRawPointer.allocate(byteCount: 16, alignment: 1)

ptr.assumingMemoryBound(to: Int.self).pointee = 11
(ptr + 8).assumingMemoryBound(to: Double.self).pointee = 22.0//非泛型指针+8 就是偏移8个字节  和泛型指针有区别 注意!

print(unsafeBitCast(ptr, to: UnsafePointer<Int>.self).pointee)//11
print(unsafeBitCast(ptr + 8, to: UnsafePointer<Double>.self).pointee)//22.0

ptr.deallocate()

----

class Person { }
var person = Person()
var ptr = unsafeBitCast(person, to: UnsafeRawPointer.self)
print(ptr)
上一篇 下一篇

猜你喜欢

热点阅读