目录
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: ©Number)
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)
}
}
行者常至,为者常成!