In fact, there are special pointer types in Swift, and they can be seen everywhere. For example, when using KVO, we can see UnsafeMutableRawPointer, which is the corresponding void * of C language

override func observeValue(forKeyPath keyPath: String? , of object: Any? , change: [NSKeyValueChangeKey : Any]? , context: UnsafeMutableRawPointer?) {}Copy the code

Pointers in Swift, both Unsafe, are divided into two categories:

One is a MutablePointer that you can modify to point to something

  1. UnsafeMutablePointer < Type > Generic class Pointers can be explicitly typed similar to C’s Type *
  2. UnsafeMutableRawPointer a non-generic class similar to void * in C

You can do this if you just want to use a pointer to a variable to modify or view what it points to. Declare a function that uses a mutable pointer to the variable of the input parameter to modify and access the memory of the pointed variable.

var str = "Hello, Playground "func test1(_ PTR :UnsafeMutablePointer<String>){PTR. Pointee +=" Swift"// Playground "func test2(_ PTR  :UnsafeMutableRawPointer){ ptr.storeBytes(of: "Hello, Swift", as: Test1 (&str) print(STR)// playground Swift test2(&str) print(STR)//Hello, SwiftCopy the code

The other is that you cannot change the type of pointer to which the pointer points

  1. UnsafePointer< Type > The generic class is similar to C Const Type *
  2. UnsafeRawPointer non-generic is similar to Const Void * in C

How to use it: Declare a function that uses an immutable pointer to access the memory of the variable it points to

Func test3(_ PTR :UnsafePointer<String>){print(PTR. Pointee)// The generic immutable pointer accesses the instance referenced by this pointer. } var name = "Anthony" test3(&name)//Anthony func test4(_ ptr :UnsafeRawPointer) { print(ptr.load(as: String. Self)// A non-generic immutable pointer accesses the instance referenced by this pointer. } test4(&name)//AnthonyCopy the code

Gets a pointer to a variable

A pointer to the corresponding variable can be obtained by calling withUnsafeMutablePointer as follows

var score = 100 var ptr1 = withUnsafeMutablePointer(to: &score) {(point) -> UnsafeMutablePointer<Int> in return point} &score){$0} print("ptr1===",ptr1)//ptr1=== 0x000000010bda1530 print("ptr2===",ptr2)//ptr2=== 0x000000010bda1530 Var ptr3 = withUnsafeMutablePointer(to: &score) {UnsafeMutableRawPointer($0)// Convert generic class pointer to non-generic class pointer} ptr3.storeBytes(of: 150, as: int.self)Copy the code

Gets the address value of a class object in heap space

There are three steps to get the address value of a class object in the heap space:

  1. Gets a pointer variable to the memory address of the object.
  2. Retrieves the value of the address to which the pointer points.
  3. Get the memory address of the object from the address to which the pointer points.
var student = Student.init(age: 20) var ptr = withUnsafePointer(to: &student) {UnsafeRawPointer($0)} let address = ptr.load(as: Var objectPtr = UnsafeRawPointer(bitPattern: Print (objectPtr)//Optional(0x0000600001866120)Copy the code

Create a pointer

Getting a pointer to an existing variable. Now let’s learn how to create a pointer. If you only need to store ints, you can simply use malloc to allocate a memory address to a pointer variable

Var PTR = malloc(24) var PTR = malloc(24) .storeBytes(of: 2020, as: int.self)// Save 2020 PTR in the first eight words? .storeBytes(of: 08, toByteOffset: 8, as: int.self)// Access 08 PTR in 8-16 bytes? .storeBytes(of: 01, toByteOffset: 16, as: int.self)// Print ((PTR? .load(as: Int.self))!) //2020 print((ptr? .load(fromByteOffset: 8, as: Int.self))!) // 8 print((ptr? .load(fromByteOffset: 16, as: Int.self))!) // 16 free(PTR)// Note that this part of memory is not ARC managed, we need to manually destroyCopy the code

If you want to generate a pointer to various data types you need to use UnsafeMutablePointer

Var genericPtr = UnsafeMutablePointer<String>. Allocate (capacity: 3)// Create a pointer to a String that can store up to 3 strings. For example, if a String occupies 16 bytes in Swift, the allocated size is 48 bytes Succeeded (to: "Hello")// First part memory storage Hello GenericPTTR. "Succeeded ")// Use the next allocated memory (that is, the 16-32 bytes in the memory) genericptr.succeeded ().succeeded ().initialize(to: "Swift") // MARK: - Print (genericPtr. Pointee) // "Hello" print((genericPtr + 1). Pointee) // "World" print((genericPtr + 1) 2).pointee) // "Swift" print(genericPtr[0]) // "Hello" print(genericPtr[1]) // "World" print(genericPtr[2]) // "Swift" Genericptr. deinitialize(count: 3) Genericptr. deallocate()// Free memoryCopy the code

Create a pointer to a custom class

Var objcPtr = UnsafeMutablePointer<Teacher>. Allocate (capacity: Objcptr. initialize(to: Teacher. Init (gradeClass: Succeeded (tO: Teacher. Init (gradeClass: "Succeeded 1 grade 2 ", Name: succeeded ()) objcptr.succeed (). (objcPtr + 2). Initialize (to: Teacher. Init (gradeClass: "1 grade 5 class ", name: "Teacher zhang")) / / print (objcPtr. Pointee. Description) / / class 2, grade 3 Miss li print (objcPtr. Successor (.) pointee. Description) / / class 1, grade 2 Teacher wang Succeeded ().goantecedent ().goantecedent ().goantecedent (). Objcptr.deallocate (); // Locate the Teacher object objcptr.deallocate ()Copy the code

Pointers

If you declare a pointer of arbitrary type and want to cast it to a pointer of a specific type, you can use unsafeBitCast, as illustrated below.

Father {var name = "Father" init() {}} Father {var name = "Father" init() {}} Father {var name = "Father" init() {} UnsafeMutableRawPointer. The allocate (byteCount: 64, alignment: 1) / / assigned a size of 64 bytes of memory PTR. AssumingMemoryBound (to: Son.self).pointee = son.init ()// Son (PTR + 32).sumingmemoryBound (to: Father. Self).pointee = Father. Init () // Allocate the next 32 bytes to Father print(unsafeBitCast(PTR, to: UnsafePointer<Son>.self).pointee.name)// This pointer is of a self-contained type similar to void *. Now convert it to UnsafePointer<Son print(unsafeBitCast(ptr + 32 , to: UnsafePointer<Father>. Self).pointee.name)// Convert any pointer to UnsafePointer<FatherCopy the code

// unsafeBitCast is a cast that ignores the data type and does not change the original memory data due to the data type change

Print (unsafeBitCast(PTR, to:) print(unsafeBitCast(PTR, to:) unsafeBitCast(PTR, to:) UnsafePointer<Father>.self).pointee)//__lldb_expr_123.Son // PTR.Copy the code

The first 32 bytes of memory pointed to by the PTR pointer store an instance object of type Son. Although we convert the PTR pointer to type Father, we do not change the memory data.

The relevant Swift code is here, you can refer to the article. It’s a little easier to understand.

Swift pointer let’s talk about here, any mistakes or deficiencies, welcome to point out. I hope to have more discussions with you.