Handle pointers such as UnsafePointer <T> in Swift

This article is the 12th day article of Swift Advent Calendar 2014.

The Advent Calendar is just around the corner. December is already the 12th, which makes you feel the end of the year.

Personally, as I get older, I feel that the year is very early. The ancestor also left the words ** "The number of days experienced in a year is the reciprocal of age" **. (Let's not make a mistake that the value does not change so much even if the reciprocal of 1 or more is taken)


Now let's move on to the topic of Swift.

The language design for Swift is good, but the support for Xcode and the compiler are still so high that I've never been motivated to make an app by myself. (If you optimize a certain code, it may loop infinitely)

This time, it's not about the compiler, but about accessing memory directly using pointers.

Use pointers in Swift

Swift C language compatibility

First, Swift has a C-compatible API.

For example, while creating an iOS or Mac application

var error: NSError? = nil
if !_fetchedResultsController!.performFetch(&error) {
     println("Unresolved error \(error), \(error?.localizedDescription)")
}
return _fetchedResultsController!

You should remember writing. (Located in the project's Core Data template)

The address of the variable declared in this NSError? Is passed to the argument of performFetch.

If you go to see the definition of performFetch

func performFetch(error: NSErrorPointer) -> Bool

And NSErrorPointer is aliased as below.

typealias NSErrorPointer = AutoreleasingUnsafeMutablePointer<NSError?>

The ʻAutoreleasingUnsafeMutablePointer ` here works as a pointer in C language.

ʻUnsafe Pointer `etc.

By nature, Swift does not have direct access to memory.

However, it is possible by using ʻUnsafePointer ` etc. in the API compatible with C language mentioned above.

I mentioned ʻUnsafe Pointer `** etc. ** from earlier, but there are other types in the official reference.


For return types, variables, and arguments, the following mappings apply:

C Syntax Swift Syntax
const Type * UnsafePointer<Type>
Type * UnsafeMutablePointer<Type>

For class types, the following mappings apply:

C Syntax Swift Syntax
Type * const * UnsafePointer<Type>
Type * __strong * UnsafeMutablePointer<Type>
Type ** AutoreleasingUnsafeMutablePointer<Type>

As mentioned above, the pointer types are

It is divided into.

as a feature

--Use nil in Swift to represent NULL in C --Converted to ʻUnsafePointer ` if necessary

About implementation

Let's actually use these.

This time, as an example of a pointer, I will introduce a swapByPointer function. (The swap function appears frequently in the pointer example.)

I want the type to be any type, so I use generics.

** swapByPointer function **

func swapByPointer<T>(x: UnsafeMutablePointer<T>, y: UnsafeMutablePointer<T>) {
    let z: T = x.memory
    x.memory = y.memory
    y.memory = z
}

call

var a: Int = 10
var b: Int = 20

// a = 10, b = 20
println("a = \(a), b = \(b)")

// Swap
swapByPointer(&a, &b)

// a = 20, b = 10
println("a = \(a), b = \(b)")

It looks like this.

I define a normal swap function and pass the address as its argument. We are assigning directly to the memory pointed to by the address in the function.

In-Out (bonus)

I think there is a tsukkomi of "No, isn't it simpler to use such ʻinout`?"

This time I want to use ** pointer ** explicitly, so I don't use ʻinout`.

If you are asking "What is ʻinout`?", Please read the code below.

** swapByInout function (inout version) **

func swapByInout<T>(inout x: T, inout y: T) {
    let z: T = x
    x = y
    y = z
}

call

var a: Int = 10
var b: Int = 20

// a = 10, b = 20
println("a = \(a), b = \(b)")

// Swap
swapByInout(&a, &b)

// a = 20, b = 10
println("a = \(a), b = \(b)")

Memory management

The previous reference was from the address of the variable already allocated, but if you are familiar with C language, it will be "** memory alloc ** !?".

Of course there is.

alloc

// Use UnsafeMutablePointer<T>
typealias IntPointer = UnsafeMutablePointer<Int>
// C Language:
//  typedef int *IntPointer;

var a_ptr = IntPointer.alloc(1)
// C Language:
//  int *a_ptr = (int *)malloc(1 * sizeof(int));
//  IntPointer a_ptr = (IntPointer)malloc(1 * sizeof(int));
//   or
//  int *a_ptr = (int *)calloc(1, sizeof(int));
var b_ptr = IntPointer.alloc(1)

a_ptr.memory = a
// C Language:
//  *a_ptr = a;
b_ptr.memory = b

// a_ptr.memory = 10, b_ptr.memory = 20
println("a_ptr.memory = \(a_ptr.memory), b_ptr.memory = \(b_ptr.memory)")

// Swap
swapByPointer(a_ptr, b_ptr)

// a_ptr.memory = 20, b_ptr.memory = 10
println("a_ptr.memory = \(a_ptr.memory), b_ptr.memory = \(b_ptr.memory)")

// Destroy
a_ptr.dealloc(1)
// C Language:
//  free(a_ptr);
b_ptr.dealloc(1)

As a comment, I also wrote down the situation in C language.

There are three codes that need explanation: ʻalloc, dealloc, and memory`.

var p = UnsafeMutablePointer.alloc(num)

In C language

Type *p = (Type *)malloc(num * sizeof(Type));
// or
Type *p = (Type *)calloc(num, sizeof(Type));

It will be.

Specify the number of declared types in num to secure the required memory size.

p.dealloc(num)

In C language

free(p);

I'm releasing it.

p.memory

In C language

*p

is. Used to refer to the value in the address.


Generally, if you know this degree, you can build Swift with the idea of C language.

in conclusion

I have given this code to Gist, so please refer to it if you like.

https://gist.github.com/kaneshin/564fc0780e0d1c9cac7d

Also, if you talk about pointers, you should be asked ** "What is a function pointer?" **.

Of course, there is also a compatible API for working with function pointers. Let's say that someone wants to know, or will introduce it when the ** stock number of this article reaches about 100 **.

It was such a great deal, but I don't think there is an article in Japanese dealing with pointers in Swift, so please touch it if you like.

Recommended Posts

Handle pointers such as UnsafePointer <T> in Swift
Handle C char ** well in Swift
Get contextual information such as HttpServletRequest in Jersey
[Swift] Get document Id as well as document in Cloud Firestore
Treat Swift functions and closures as C function pointers
[Swift] Get key as well as value in Realtime database