JHHK

欢迎来到我的个人网站
行者常至 为者常成

16、内存访问冲突、指针

目录

do的用法

//一、do的用法
func doUse() -> Void {
    //局部作用域
    do{
        let a:Int = 10
        let b:Int = 11
        print(a,b)
    }
    
    //局部作用域
    do{
        let a:Int = 10
        let b:Int = 11
        print(a,b)
    }
}

内存访问冲突

//二、内存访问冲突
func balance(_ x: inout Int, _ y: inout Int) {
    let sum = x + y
    x = sum / 2
    y = sum - x
}
struct Player {
    var name: String
    var health: Int
    var energy: Int
    mutating func shareHealth(with teammate: inout Player) {
        balance(&teammate.health, &health)
    }
}
var tulpe = (health: 10, energy: 20)
//balance(&tulpe.health, &tulpe.energy)// Error
var holly = Player(name: "Holly", health: 10, energy: 10)
//balance(&holly.health, &holly.energy)// Error
func conflicAccessMemory(){
    /**
     内存访问冲突会在两个访问满足下列条件时发生:
     至少一个是写入操作
     它们访问的是同一块内存
     它们的访问时间重叠(比如在同一个函数内)
     */
    
    
    //1、内存访问冲突
    do{
        print("--------1----------")
        var number = 1
        func add(num:inout Int){
            num = num + number
        }
        
        //报错:内存访问冲突
        //Simultaneous accesses to 0x10062d0b0, but modification requires exclusive access.
        //同时访问0x10062d0b0,但修改需要独占访问。
        //add(num: &number)
        
        //解决办法
        var copyNumber = number
        add(num: &copyNumber)
        number = copyNumber
        print(number)
    }
    
    
    //2、内存访问冲突
    do{
        print("--------2----------")
        
        var num1 = 42
        var num2 = 30
        balance(&num1, &num2) // OK
        //balance(&num1, &num1) // Error

       
        var oscar = Player(name: "Oscar", health: 10, energy: 10)
        var maria = Player(name: "Maria", health: 5, energy: 10)
        oscar.shareHealth(with: &maria) // OK
        //oscar.shareHealth(with: &oscar) // Error
        
        //见全局变量 tulpe

        //见全局变量 hollype
    }
    
    
    //3、内存访问冲突
    do{
        print("----------3---------")
        
        /**
        如果下面的条件可以满足,就说明重叠访问结构体的属性是安全的
            你只访问实例存储属性,不是计算属性或者类属性
            结构体是局部变量而非全局变量
            结构体要么没有被闭包捕获要么只被非逃逸闭包捕获
        */
        
        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()
    }
}

指针的应用示例

/// 三、指针的应用示例
func swiftPointerUse() -> Void {
    
    //1、
    do{
        print("-------1------")
        /**
         Swift中也有专门的指针类型,这些都被定性为“Unsafe”(不安全的),常见的有以下4种类型
         UnsafePointer<Pointee> 类似于 const Pointee *
         UnsafeMutablePointer<Pointee> 类似于 Pointee *
         UnsafeRawPointer 类似于 const void *
         UnsafeMutableRawPointer 类似于 void *
         */
        
        var age = 10
        func test1(ptr:UnsafePointer<Int>){
            print("----------test1----------")
            print(ptr.pointee)
            //UnsafePointer 相当于 const int * 不允许改变内存
            //ptr.pointee = 20
        }
        test1(ptr: &age)
        
        func test2(ptr:UnsafeMutablePointer<Int>){
            //UnsafeMutablePointer 相当于 int *  可以取值 可以赋值
            print("----------test2----------")
            print(ptr.pointee)
            ptr.pointee = 20
            print(ptr.pointee)
        }
        test2(ptr: &age)

        
        func test3(ptr:UnsafeRawPointer){
            print("----------test3----------")
            //UnsafeRawPointer 相当于 const void* 不允许更改内存 并且不知道类型 使用 load方法并传入类型信息
            let temp = ptr.load(as: Int.self)
            print(temp)
        }
        test3(ptr: &age)


        func test4(ptr:UnsafeMutableRawPointer){
            print("----------test4----------")
            //UnsafeMutableRawPointer 相当于 void* 允许更改内存 但不知道类型 storeBytes方法并传入类型信息和值

            var temp = ptr.load(as: Int.self)
            print(temp)
            ptr.storeBytes(of: 40, as: Int.self)
            
            temp = ptr.load(as: Int.self)
            print(temp)
        }
        test4(ptr: &age)
        
        /**
         ----------test1----------
         10
         ----------test2----------
         10
         20
         ----------test3----------
         20
         ----------test4----------
         20
         40
         */
    }
    
    
    //2、数组的使用
    do{
        print("--------2---------")
        
        let arr = NSArray(objects: 11,22,33,44)
        
        //stop 类型为 UnsafeMutablePointer<ObjCBool>
        arr.enumerateObjects { (element, index, stop) in
            if index == 2 {
                
                //类似于break的作用 但不同
                //break会在此处结束循环
                //此处会将该轮循环执行完 在结束循环
                stop.pointee = true
                
            }
            print(element,index)
        }
        
        print("-----------------")
        
        //swift中遍历数组建议使用下面方法:
        for (index,element) in arr.enumerated() {
            print(index,element)
            if index == 2 {
                break
            }
        }
    }
}

获得指针

/// 一、获得指针
func getPointer() -> Void {
    //1获得指针
    do{
        print("---------1----------")
        var age = 10
        let ptr = withUnsafePointer(to: &age) { $0 }
        print(ptr,ptr.pointee)
        
        let ptr2 = withUnsafeMutablePointer(to: &age) { (p) -> UnsafeMutablePointer<Int> in p}
        ptr2.pointee = 20
        print(ptr2,ptr2.pointee)
        
        
        let ptr3 = withUnsafePointer(to: &age) { UnsafeRawPointer($0)}
        print(ptr3 , ptr3.load(as: Int.self))
        
        
        let ptr4 = withUnsafeMutablePointer(to: &age) { UnsafeMutableRawPointer($0)}
        ptr4.storeBytes(of: 40, as: Int.self)
        print(ptr4 , ptr4.load(as: Int.self))
    }
    
   
    
    //2、获取指向堆空间的地址
    do{
        print("---------2----------")
        class Person{}
        var person = Person()
        let ptr = withUnsafePointer(to: &person){UnsafeRawPointer($0)}
        print("ptr:",ptr)//变量地址
        
        let personObjAddress = ptr.load(as: UInt.self)
        print("personObjAddress:",personObjAddress)//变量存储数据
        
        let heapPointer = UnsafeRawPointer(bitPattern: personObjAddress)
        print("heapPointer",heapPointer as AnyObject)//堆空间地址
    }
}

创建指针

//二、创建指针
func creatPointer() -> Void {
    
    //方法一:
    do{
        print("--------1---------")

        //在堆空间开辟16字节的空间 UnsafeMutableRowPointer?
        let ptr = malloc(16)
        print(ptr)
        //创建
        ptr?.storeBytes(of: 10, as: Int.self)
        ptr?.storeBytes(of: 20, toByteOffset: 8, as: Int.self)
        //取
        print(ptr?.load(as: Int.self))//此处为什么是可选类型 是否与 ptr 是可选类型有关?
        print(ptr?.load(fromByteOffset: 8, as: Int.self))
        //销毁
        free(ptr)
        
    }
    
    
    //方法二:
    do{
        print("--------2---------")
        let 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)
        print(ptr.load(as: Int.self)) // 11
        print(ptr.advanced(by: 8).load(as: Int.self)) // 22
        ptr.deallocate()
    }
    
    
    
    //方法三:
    do{
        print("--------3---------")

        //注意是 capacity 3个 int
        let ptr = UnsafeMutablePointer<Int>.allocate(capacity: 3)
        //初始化内存的前8个字节
        ptr.initialize(to: 11)
        //后继
        ptr.successor().initialize(to: 22)
        //后继
        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()
    }
    
    
    //方法四:注意内存泄漏问题
    do{
        print("--------4---------")

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

        let ptr = UnsafeMutablePointer<Person>.allocate(capacity: 3)
        
        ptr.initialize(to: Person(age: 10, name: "Jack"))
        (ptr + 1).initialize(to: Person(age: 11, name: "Rose"))
        (ptr + 2).initialize(to: Person(age: 12, name: "Kate"))
        
        // Jack deinit
        // Rose deinit
        // Kate deinit
        //如果不调用反初始化器 person对象不会销毁
        ptr.deinitialize(count: 3)
        ptr.deallocate()
    }
}

交换指针类型

/// 三、交换指针类型
func swichPointerType() -> Void {
    do{
        print("--------1-------")
        let ptr = UnsafeMutableRawPointer.allocate(byteCount: 16, alignment: 1)
        ptr.assumingMemoryBound(to: Int.self).pointee = 11
        (ptr + 8).assumingMemoryBound(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()
    }
    
    do{
        print("--------2-------")
        //unsafeBitCast是忽略数据类型的强制转换,不会因为数据类型的变化而改变原来的内存数据
        //类似于C++中的reinterpret_cast
        
        //创建指向堆空间的指针的另外一种实现方法
        class Person {}
        let person = Person()
        
        
        let personObjAddress = unsafeBitCast(person, to: UInt.self)
        let ptr = UnsafeRawPointer(bitPattern: personObjAddress)
        print(ptr!)
        
        //理解 unsafeBitCast的本质
        let ptr1 = unsafeBitCast(person, to: UnsafeRawPointer.self)
        print(ptr1)
        
        
        //通过unsafeBitCast查看内存地址
        var age = 10
        let ageAddress = withUnsafePointer(to: &age){$0}
        print(ageAddress)
        let content = unsafeBitCast(ageAddress, to:UInt.self)
        print(content)
    }

}

行者常至,为者常成!





R
Valine - A simple comment system based on Leancloud.