Swift USES instances in conjunction with C language Pointers

  • 2020-05-10 22:59:13
  • OfStack

Pointers are often required for Objective-C and API for C. The data types in Swift are all native to Cocoa API, and not only that, Swift automatically handles some of the most commonly used situations where a pointer is passed as a parameter. In this article, we'll look at getting C language Pointers to work with variables, arrays, and strings in Swift.
Parameter Pointers for input/output

C and Objective-C do not support multiple return values, so Pointers are often used in Cocoa API as a way to pass additional data between methods. Swift allows Pointers to be used as inout arguments, so you can use the symbol & to pass a reference to a variable as a pointer argument. For example, the getRed(_:green:blue:alpha:) method in UIColor needs four CGFloat* Pointers to receive color composition information, and we use & to capture this composition information as a local variable:


var r: CGFloat = 0, g: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 0
color.getRed(&r, green: &g, blue: &b, alpha: &a)

Another common situation is the usage of NSError in Cocoa. Many methods use an NSError** parameter to store possible error information. For example, we use NSFileManager's contentOfDirectoryAtPath(_:error) method to list the contents of a directory and point potential errors to an NSError? Variables:

var maybeError: NSError?
if let contents = NSFileManager.defaultManager()
    .contentsOfDirectoryAtPath("/usr/bin", error: &maybeError) {
    // Work with the directory contents
} else if let error = maybeError {
    // Handle the error
}

For security, Swift requires that the variables passed by & be initialized. It is not clear whether this method will attempt to read the data from the pointer before writing it.

#### # is used as a pointer to an array

In C, the connection between an array and a pointer is 10 points tight, while Swift allows an array to be used as a pointer, making it easier to work with the array based C language, API. A fixed array can be passed directly using a constant pointer, and a variable array can be passed using the & operator. Just like input/output parameter pointer 1. For example, we can add two arrays, a and b, using the vDSP_vadd method in the Accelerate framework, and write the result to the third array, result.


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]

# is used as a pointer to the string argument

The C language USES cont char* Pointers as the basic way to pass strings. String in Swift can be passed to a method as an const char* pointer of infinite length UTF-8 encoding. For example, we can pass a string directly to a standard C and POSIX library method


puts("Hello from libc")
let fd = open("/tmp/scratch.txt", O_WRONLY|O_CREAT, 0o666) if fd < 0 {
    perror("could not open /tmp/scratch.txt")
} else {
    let text = "Hello World"
    write(fd, text, strlen(text))
    close(fd)
}

Security of # pointer parameter conversion

Swift has worked hard to make interaction with C language Pointers easier, as they are widely available in Cocoa while maintaining a certain level of security. However, your Swift code is potentially insecure when compared to other Swift code that interacts with Pointers in the C language, so be careful. Particular attention should be paid to:

● these transformations are not safe to use if the caller saves the data of the C pointer in order to use it again after its return value. The converted pointer is only guaranteed to be valid for the duration of the call. Even if you pass the same variable, array, or string as a multi-pointer argument again, you'll get a different pointer each time. This exception is stored globally or statically as a variable. You can safely use this address as a pointer to permanent 1. For example: when used as one KVO context parameter.

● overflow checking is not mandatory when the pointer type is Array or String. API based on C cannot increase the size of an array or a string, so before you pass it to API based on C, you must make sure that the array or character is the right size.

If you do not follow the above instructions when you need to use the cursor-based API, or if you override the Cocoa method that accepts pointer arguments, you can use the unprocessed memory directly in Swift with unsafe Pointers. In future articles we will look at more advanced cases.


Related articles: