Apple expects pointers in swift to minimize the chance of entry, so the pointer is mapped to a generic type in swift and is also more abstract. This has partly contributed to the difficulty of using pointers in swift, especially for developers who are unfamiliar with pointers and have little experience with pointers, including myself, to use pointers in Swift is indeed a challenge. In this article, I want to start with the basics and summarize some of the common ways and scenarios for using pointers in Swift. This article assumes that you know at least what the pointer is, and if the concept of the pointer itself is not clear, it should 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, that is unsafepointer<t>. Following the consistent cocoa principle of the,unsafepointer<t> is also immutable. Of course, it also has a variable variant of,unsafemutablepointer<t>. For most of the time, pointers in C will be introduced into Swift in both types: c The const-decorated pointer corresponds to Unsafepointer (the most common should be the const char * of the C string), Other variable pointers correspond to Unsafemutablepointer. In addition, Swift has a unsafebufferpointer<t> that represents a set of consecutive data pointers, an opaque pointer copaquepointer that is not a complete structure, and so on. In addition you may have noticed that it is possible to determine that pointer types that point to content are 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 value it by the memory property, if the pointer is a mutable unsafemutablepointer<t> type, We can also assign the value to it by memory. For example, if we want to write a counter that uses pointers to manipulate memory directly, you can do this:
Copy Code code as follows:
Func Incrementor (ptr:unsafemutablepointer<int>) {
Ptr.memory + 1
}
var a = 10
Incrementor (&a)
A//11
This is similar to the C pointer, and we can pass the pointer to the variable to the method that accepts the pointer as a parameter by adding the & symbol to the variable name. In the incrementor above, we change the contents of the pointer by directly manipulating the memory attribute.
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 to the function of the inout parameter. But the difference is that in the function body we do not need to handle the pointer type, but can directly manipulate the parameters.
Copy Code code as follows:
Func Incrementor1 (inout num:int) {
num + + 1
}
var B = 10
Incrementor1 (&B)
b//11
Although the meaning of & in the parameter pass is a "variable address" as in C, there is no way in Swift to get a Unsafepointer instance directly from this symbol. Note that this is different from C:
Copy Code code as follows:
Cannot compile
Let A = 100
Let B = &a
Pointer initialization and memory management
In Swift, we can create new Unsafemutablepointer objects without directly taking the addresses of existing objects. Unlike the automatic memory management of other objects in swift, the management of pointers requires us to manually request and release the memory. There are three possible states of a unsafemutablepointer memory:
1. Memory is not allocated, which means that this is a null pointer, or has been released before;
2. The memory is allocated, but the value has not been initialized;
3. The memory is allocated and the value has been initialized.
Only the third State of the pointer is guaranteed to work properly. The Unsafemutablepointer initialization method (init) completes the work of converting from other types to unsafemutablepointer. If we want to create a new pointer, what we need to do is use Alloc: This class method. This method takes a num:int as an argument and applies the memory of the corresponding generic type with num numbers to the system. The following code requests an int size memory and returns a pointer to this memory:
Copy Code code as follows:
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:
Copy Code code as follows:
Intptr.initialize (10)
Intptr.memory is 10
After initialization is complete, we can use memory to manipulate the memory value that the pointer points to.
After use, we'd better release the contents of the pointer and the pointer itself as soon as possible. With initialize: Paired with the destroy used to destroy the object pointed to by the pointer, and alloc: The corresponding dealloc: used to release the memory previously requested. They should all be paired with:
Copy Code code as follows:
Intptr.destroy ()
Intptr.dealloc (1)
IntPtr = Nil
Note: In fact, destroy is not necessary for "trivial values" such as int, which are mapped to int in C, because these values are assigned to constant segments. But for objects like classes or instances of structs, memory leaks can occur if the pairing is not guaranteed to initialize and destroy. So there's no special consideration, no matter what in memory, guaranteed initialize: Pairing with destroy would be a good habit.
Pointer to array
In Swift's passing of an array as an argument to the C API, Swift has helped us complete the conversion, which is a good example of Apple's official blog:
Copy Code code as follows:
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 the General C API that accepts the const array, the required type is unsafepointer, not the const array corresponding to the unsafemutablepointer. When used, for const arguments, we pass the swift array directly (A and B in the example above), but for a mutable array, the preceding & after is passed (result in the previous example).
For the reference, Swift is simplified and easy to use. But if we want to use pointers to manipulate arrays directly before using memory, we need a special type: Unsafemutablebufferpointer.
The Buffer pointer is a continuous set of memory pointers that are often used to express collection types such as arrays or dictionaries.
Copy Code code as follows:
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, it is not possible to use the & symbol directly to get an address in swift, as in C. If we want to do pointers to a variable, we can use Withunsafepointer this helper method. This method accepts two parameters, the first is any type of inout, and the second is a closure. Swift converts the first input into a pointer, and then takes this converted unsafe pointer as an argument to invoke the closure. The use is probably this way:
Copy Code code as follows:
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 incrementor at the beginning of the article, except that you don't need to use the method call to convert the value to a pointer. The benefits of doing so are obvious to the pointer operations that are performed only once, and the intention of "we just want to do something about this pointer" is more clearly articulated.
Unsafebitcast
Unsafebitcast is a very dangerous operation that forces the memory that a pointer points to to be converted to the target type. Because this conversion is done outside of Swift's type management, the compiler cannot be sure that the type is actually correct, and you must know exactly what you are doing. Like what:
Copy Code code as follows:
Let arr = Nsarray (object: "Meow")
Let str = unsafebitcast (cfarraygetvalueatindex (arr, 0), cfstring.self)
STR//"Meow"
Because Nsarray can hold arbitrary nsobject objects, when we use Cfarraygetvalueatindex to derive value from it, the result will be a unsafepointer<void>. Because we understand that a string object is stored in it, you can cast it directly to cfstring.
A more common use scenario for Unsafebitcast is to convert between pointers of different types. Because the size of the pointer itself is fixed, there is no fatal problem with the type of the pointer being converted. This is common when collaborating with some C APIs. For example, there are many C API requirements for the input is Void *, which corresponds to the unsafepointer<void> in Swift. We can convert any pointer to unsafepointer in the following way.
Copy Code code as follows:
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 based on security as an important principle, although it may be long-winded, but to reiterate that direct use and manipulation of pointers in Swift should be a last resort and that they are always unable to ensure security. Migrating from a traditional C code to a seamless objective-c code to Swift is not a small project, and our code base is sure to have some collaboration with C from time to time. We can of course choose to use Swift to rewrite some of the stale code, but we may have no choice but to continue to use the C API for things as critical as security or performance. If we want to continue using those APIs, it would be helpful to know some basic swift pointer operations and the knowledge used.
For new code, try to avoid using the unsafe type, which means you can avoid a lot of unnecessary hassle. The biggest benefit that Swift brings to developers is that it allows us to develop faster and more focused development with more advanced programming ideas. Only by respecting this thought can we better enjoy the advantages of the new language. Obviously, this idea does not cover the use of unsafepointer everywhere.