Apple expects pointers in Swift to minimize the chance of appearances, so pointers are mapped to a generic type in Swift, and are also more abstract. This has contributed in part to the difficulty of using pointers in swift, especially for developers who are not familiar with pointers and have few hands-on experience (including myself), using pointers in Swift is really a challenge. In this article, I would like to start with the most basic use and summarize some common ways and scenarios for using pointers in Swift. This article assumes that you at least know what the pointer is, and if the concept of the pointer itself is not clear enough, it would be helpful to take a look at this five-minute C-pointer tutorial (or its Chinese version).
Preliminary
In Swift, pointers are represented by a special type, which is unsafepointer<t>. Following the Cocoa principle, unsafepointer<t> is also immutable. Of course, it also has a variable variant, unsafemutablepointer<t>. Most of the time, pointers in C are introduced to Swift in both types: The const-decorated pointer in C corresponds to Unsafepointer (the most common is the const char * of the C string), while the other mutable pointers correspond to Unsafemuta Blepointer. In addition, there is a unsafebufferpointer<t> in Swift that represents a set of continuous data pointers, an opaque pointer copaquepointer for an incomplete structure, and so on. In addition you may have noticed that the type of pointer to the content can be determined to be a generic struct, and we can use this generic to constrain the type that the pointer points to to provide some security.
For a unsafepointer<t> type, we can use the memory property to value it, if the pointer is a variable unsafemutablepointer<t> type, we can also pass the memory Assign a value to it. For example, if we want to write a counter that uses pointers to manipulate memory directly, you can do this:
func incrementor(ptr: UnsafeMutablePointer<Int>) {
ptr.memory += 1
}
var a = 10
incrementor(&a)
a // 11
This is similar to the pointer for C, where we can pass a pointer to this variable to the method that accepts the pointer as a parameter by adding the & symbol to the variable name. In the above incrementor we change the contents of the pointer by manipulating the memory property directly.
Similar to this approach is the use of Swift's inout keyword. We also use the & symbol to represent the address when we pass the variable into the function of the inout parameter. But the difference is that inside the function body we don't need to handle the pointer type, but we can manipulate the parameters directly.
func incrementor1(inout num: Int) {
num += 1
}
var b = 10
incrementor1(&b)
b // 11
Although & is represented as a "variable address" when the parameter is passed, there is no way to get an instance of Unsafepointer directly from this symbol in Swift. It is important to note that this differs from C:
Failed to compile
let a = 100
let B = &a
Pointer initialization and memory management
The address of an existing object cannot be taken directly in Swift, and we can still create a new Unsafemutablepointer object. Unlike the automatic memory management of other objects in Swift, the management of pointers requires that we manually request and release the memory. There are three possible states for a unsafemutablepointer memory:
- Memory is not allocated, which means that this is a null pointer, or that it has been released before
- The memory is allocated, but the value has not been initialized
- The memory is allocated and the value has been initialized
Only the third State of the pointer is guaranteed to work normally. The initialization method (init) of Unsafemutablepointer is done by converting from other types to unsafemutablepointer. If we want to create a new pointer, we need to use Alloc: This class method. The method accepts a num:int as a parameter and will request the system the number of num of the corresponding generic type of memory. The following code requests an Int-sized memory and returns a pointer to the memory:
var intPtr = UnsafeMutablePointer<Int>.alloc(1)
// "UnsafeMutablePointer(0x7FD3A8E00060)"
The next thing to do is initialize the contents of this pointer, and we can use the Initialize: method to complete the initialization:
Intptr.initialize (Ten)//Intptr.memory is 10
After the initialization, we can manipulate the memory value pointed to by the pointer.
After use, we'd better release the pointer to the content and the pointer itself as soon as possible. With initialize: The destroy used for pairing destroys the object pointed to by the pointer, and alloc: The corresponding dealloc: used to release the previously requested memory. They should all be paired with:
intPtr.destroy()
intPtr.dealloc(1)
intPtr = nil
Note that in this case, destroy is not necessary for "trivial values" such as int, which are mapped to int in C, because these values are assigned to a constant segment. But for objects like classes or struct instances, there is a memory leak if the pairing is not guaranteed to initialize and destroy. So there is no special consideration, regardless of what is in memory, guaranteed initialize: Pairing with destroy will be a good habit.
Pointer to array
When we passed an array as a parameter to the C API in Swift, Swift has helped us to complete the conversion, which is a good example of Apple's official blog:
import Accelerate
let a: [Float] = [1, 2, 3, 4]
let b: [Float] = [0.5, 0.25, 0.125, 0.0625]
var result: [Float] = [0, 0, 0, 0]
vDSP_vadd(a, 1, b, 1, &result, 1, 4)
// result now contains [1.5, 2.25, 3.125, 4.0625]
For a generic C API that accepts a const array, the required type is unsafepointer, whereas an array other than const corresponds to Unsafemutablepointer. When used, for const parameters, we directly pass in the Swift array (A and B in the above example), and for a mutable array, precede with & (result in the previous example).
For the reference, Swift is simplified and very convenient to use. But if we want to use pointers to manipulate arrays directly like memory before, we need a special type: Unsafemutablebufferpointer. Buffer Pointer is a contiguous set of memory pointers, often used to express a collection type such as an array or a dictionary.
Var array = [1, 2, 3, 4, 5]
Var arrayPtr = UnsafeMutableBufferPointer<Int>(start: &array, count: array.count)
// baseAddress is a pointer to the first element
Var basePtr = arrayPtr.baseAddress as UnsafeMutablePointer<Int>
basePtr.memory // 1
basePtr.memory = 10
basePtr.memory // 10
//Next element
Var nextPtr = basePtr.successor()
nextPtr.memory // 2
Pointer manipulation and Conversion withunsafepointer
As we said above, in Swift, you cannot use the & symbol to get an address directly in the same way as C. If we want to do pointers to a variable, we can use the helper method of Withunsafepointer. This method accepts two parameters, the first is any type of inout, and the second one is a closure. Swift converts the first input to a pointer and then takes the converted Unsafe pointer as a parameter to call the closure. This is probably the way it is used:
var test = 10
test = withUnsafeMutablePointer(&test, { (ptr: UnsafeMutablePointer<Int>) -> Int in
ptr.memory += 1
return ptr.memory
})
test // 11
Here we actually do the same thing as the beginning of the article Incrementor, the difference is that you don't need to convert the value to a pointer by calling the method. The benefits of doing so are obvious for those pointers that will only be executed once, and the intention of "we just want to do something about this pointer" is expressed more clearly.
Unsafebitcast
Unsafebitcast is a very dangerous operation, which forces a pointer-pointing memory to force a bitwise conversion to the target type. Because this conversion is done outside of the type management of Swift, the compiler cannot ensure that the resulting type is really correct, and you must know exactly what you are doing. Like what:
let arr = NSArray(object: "meow")
let str = unsafeBitCast(CFArrayGetValueAtIndex(arr, 0), CFString.self)
str // “meow”
Because Nsarray can store arbitrary nsobject objects, when we use Cfarraygetvalueatindex to derive values from it, the result will be a unsafepointer<void>. Since we understand that the String object is stored, you can cast it directly to cfstring.
About unsafebitcast a more common usage scenario is the conversion between different types of pointers. Because the size of the pointer itself is certain, there is no fatal problem with the type of pointer being converted. This is common when collaborating with some C APIs. For example, there are many C API-required inputs that are void * and correspond to unsafepointer<void> in Swift. We can convert any pointer to unsafepointer in the following way.
Var count = 100
Var voidPtr = withUnsafePointer(&count, { (a: UnsafePointer<Int>) -> UnsafePointer<Void> in
Return unsafeBitCast(a, UnsafePointer<Void>.self)
})
// voidPtr is UnsafePointer<Void>. Equivalent to void in C *
// convert back to UnsafePointer<Int>
Var intPtr = unsafeBitCast(voidPtr, UnsafePointer<Int>.self)
intPtr.memory //100
Summarize
Swift is designed to be safe as an important principle, although it may be a bit verbose, but it is to reiterate that direct use and manipulation of pointers in Swift should be a last resort, and they are never secure. Migrating from traditional C code and seamless objective-c code to Swift is not a small project, and our code base is sure to come up with some areas of collaboration with C from time to time. We can of course choose to rewrite some of the stale code using Swift, but we may have no choice but to continue using the C API for parts that are critical to security or performance. If we want to continue to use those APIs, it would be helpful to know some basic Swift pointer operations and usage knowledge.
For new code, try to avoid using the type of unsafe, which means you can avoid a lot of unnecessary hassles. The biggest benefit that Swift brings to developers is that we can use more advanced programming ideas for faster and more focused development. Only by respecting this thought can we enjoy the advantages of this new language better. Obviously, this idea does not include the use of unsafepointer everywhere:)
- This article is from: Linux Learning Tutorial Network
Pointers in Swift use the