Okay, I'll start with something simple. Look at the main content of the article.
In most cases, C language pointers can be imported into Swift in two ways:
UnsafePointer & ltT & gt
UnsafeMutablePointer & ltT & gt
T Here is the equivalent Swift type of type C, the pointer declared as constant is imported as UnsafePointer, and the non-constant pointer is imported as UnsafeMutablePoinger.
Here are some examples:
C:
void my function(const int * myconstinpointer);
Swift:
func my function(myconstinpointer:unsafe pointer & lt; Int32 >)
C:
void myOtherFunction(unsigned int * myunsignedint pointer);
Swift:
func myOtherFunction(myunsignedint pointer:unsafmutablepointer & lt; UInt32 & gt)
C:
void itakeavoidepointer(void * avoidepointer);
Swift:
func itake avoid pointer(avoid pointer:unsafmutable pointer & lt; Void & gt)
If you don't know the type of pointer, such as a pointer declared as a prefix, use COpaquePointer.
C:
Construct something;
void iTakeAnOpaquePointer(struct SomeThing * SomeThing);
Swift:
func iTakeAnOpaquePointer(someThing:COpaquePointer)
Pass a pointer to a Swift object.
In many cases, passing a pointer to a Swift object is as simple as using the inout operator, which is similar to the and operator in C language.
Swift:
Let myInt: = 42
My function (& ampmyInt)
var myUnsignedInt: UInt = 7
My Other Functions (& ampmyUnsignedInt)
Here are two very important but easily overlooked details.
1. When using inout operator, variables declared with var and constants declared with let are converted into UnsafePointer and UnsafeMutablePoinger respectively. If you don't pay attention to the types in the original code, it is easy to make mistakes. You can try to pass an UnsafeMutablePoinger to an unsafe place, and the compiler will report an error.
2. This operator only takes effect when Swift values and references are passed as context of function parameters, and function parameters only accept two types: UnsafePointer and UnsafeMutablePoinger. You can't get these pointers in other contexts. For example, the following code is invalid and will return a compilation error.
Swift:
Let x = 42.
Let y = & ampx
You may need to interoperate with the API from time to time. Gets or returns a null pointer instead of an explicit type. Unfortunately, this practice is so common in C that it is impossible to specify a universal type.
C:
void takesAnObject(void * the object);
If you are sure what kind of parameters the function needs to take, you can use withUnsafePointer and unsafeBitCast to cast an object to a null pointer. For example, suppose takesAnObject needs to get a pointer to int.
Var test = 42
with unsafepointer(& amp; test,{(ptr:unsafe pointer & lt; Int & gt)-& gt; invalidate
var void ptr:unsafe pointer & lt; Void & gt= unsafeBitCast(ptr,UnsafePointer & ltVoid & gt。 Self)
takesAnObject(voidPtr)
})
To convert it, we first need to call withUnsafeMutablePointer, which contains two parameters.
The first parameter is the t-type inout operator, and the second parameter is (unsafe pointer)->; Closure of ResultType. The function calls the closure through a pointer to the first parameter, then passes it as the only parameter of the closure, and finally the function returns the result of the closure. In the above example, the type of the closure is set to Void, so no return value will be returned. Examples of return values are as follows:
let ret = withounsafepointer(& amp; test,{(ptr:unsafe pointer & lt; Int & gt)-& gt; Int32 inches
var void ptr:unsafe pointer & lt; Void & gt= unsafeBitCast(ptr,UnsafePointer & ltVoid & gt。 Self)
Returns takesanobjectandreturnsanint (void ptr)
})
println(ret)
Note: You need to modify the pointer by yourself, and you can complete the modification through Variant with Unsafe Mutable Pointer.
For convenience, Swift also includes variants that pass two pointers:
var x: Int = 7
var y: Double = 4
with unsafe pointers(& amp; x & amp; y,{(ptr 1:unsafe pointer & lt; Int & gt,ptr 2:unsafe pointer & lt; Double & gt)-& gt; invalidate
var void ptr 1:unsafe pointer & lt; Void & gt= unsafeBitCast(ptr 1,UnsafePointer & ltVoid & gt。 Self)
var void ptr 2:unsafe pointer & lt; Void & gt= unsafeBitCast(ptr2,UnsafePointer & ltVoid & gt。 Self)
takesTwoPointers(void ptr 1,voidPtr2)
})
About unsafeBitCast
UnsafeBitCast is an extremely dangerous operation. The document describes it as "forcibly converting something into the same length as other things". We can use it safely in the above code because we simply convert different types of pointers, and the length of these pointers is the same. That's why we have to call withUnsafePointer to get UnsafePointer, and then convert it into UnsafePointer.
This can be confusing at first, especially when dealing with the same type as poInters, such as int in Swift (in all available platforms, the length of pointers is one character, and the length of int is also one character).
For example, it is easy to make the following mistakes:
var x: Int = 7
Let xPtr = unsafeBitCast(x, unsafe pointer < lt void >. Self)
The intention of this code is to get a pointer and pass it to X, which will cause misunderstanding. Although compilation can be passed and run, it will lead to unexpected errors. This is because instead of getting a pointer and passing it to X, C API receives a pointer at 0x7 or other locations.
Because unsafeBitCast requires equal lengths of types, it is not so insidious when trying to convert Int8 or byte integers.
var x: Int8 = 7
Let xPtr = unsafeBitCast(x, unsafe pointer < lt void >. Self)
This code will only cause unsafeBitCast to throw an exception and crash the program.
Interacting with Structure in C Language
Let's show this part with practical examples. If you want to retrieve the system information that the computer is running, there is a CAPI: UNAME (2) to achieve the goal. It receives pointers to data structures and populates the provided objects with system information, such as OS name and version or hardware identifier. But there is a problem here. The structure of importing Swift is as follows:
Structure name {
Var sysname: (Int8, Int8, ... 253 times ... Int8)
Var nodename: (Int8, Int8, ... 253 times ... Int8)
Var release: (Int8, Int8, ... 253 times ... Int8)
Var version: (Int8, Int8, ... 253 times ... Int8)
Var machine: (Int8, Int8, ... 253 times ... Int8)
}
Swift imports the array words in C as tuples, and the default initialization program requires each field to have a value, so if you do it in the usual way of Swift, it will become:
Var name = utsname(sysname: (0 0,0,0, ..., 0), node name: (0,0,0, ... 0), etc.)
utsname(& amp; Name)
Var machine = name. machine
printer
This is not a good method. One more question. Because the machine field in utsname is a tuple, when println is used, 256-bit Int8 will be output, but actually only the first few ASCII values of the string are what we need.
So, how to solve this problem?
UnsafeMutablePointer in Swift provides two methods, alloc(Int) and dealloc(Int), to allocate and deallocate the quantization parameters of template T respectively. We can use these APIs to simplify our code:
let name = unsafmutablepointer & lt; utsname & gt。 Allocation (1)
Uname (name)
let machine = withounsafepointer(& amp; name.memory.machine,{(ptr)-& gt; String? exist
let int8Ptr = unsafeBitCast(ptr,UnsafePointer & ltInt8 >。 Self)
Returns String.fromCString(int8Ptr)
})
name.dealloc( 1)
If let m = machine {
Print Length (m)
}
The first step is to call withUnsafePointer, pass the tuple of the machine to it, and inform it that our closure will return an extra string.
In the closure, we convert the pointer to UnsafePointer, which is the most equivalent expression of the value. In addition, Swift's string contains a class method to initialize UnsafePointer, where CChar is an alias of type Int8, so we can pass our new pointer to the initializer and return the required information.
After obtaining the result of withUnsafePointer, we can test whether it is a conditional statement of let and print out the result. For this example, it outputs the expected field "x86_64".
abstract
Finally, a disclaimer. Using unsafe APIs in Swift should be regarded as the last resort because they are potentially unsafe. When we convert the legacy C and Objective-C codes into Swift, it is likely that we will continue to need these APIs to be compatible with existing tools. However, when using unsafe pointer and unsafeBitCast as the first choice, we should always be skeptical and look for other better solutions.
The new code should conform to the language habit as much as possible, and do not use unsafe API in Swift code. As a software developer, you should know how to use your tools and where to use them and where not to use them. Swift has brought modernization to OS X and iOS development, and we must respect its concept.