This translation is exclusively licensed to SWIFTGG
Original link: objective-c pointers and Swift 2: A Simple Guide
Original Date: 2015/08/23
Translator: Mmoaay
Proofreading: NUMBBBBB
Finalized: Shanksyang
This article was written on August 23, 2015 and is compatible with Xcode7 Beta and Swift 2
Use OBJECTIVE-C in Swift to read the C pointer in Swift
The following Objective-c method returns a int
pointer, or C-term (int *)
:
@interface Span class= "Hljs-title" >pointerbridge : nsobject { int count;} -(int *) getcountptr; @end @implementation Pointerbridge -(instancetype) init {self = [super init]; if (self ) {count = 23 ; } return self ;} -(int *) getcountptr {return &count;} @end
The code above defines a PointerBridge
class that contains a getCountPtr
method that returns a int
type memory address with a value of 23. This Int
is actually count
an instance, which is assigned a value of 23 in the constructor method init
.
I put this code in a OBJECTIVE-C header file and import the header file into my bridge header file (xxx-bridging-header.h) so that it can be used in Swift. Then I create a named instance in Swift bridge
PointerBridge
and get getCountPtr()
The return value of the method ...
letPointerBridge()let theInt = bridge.getCountPtr()print(theInt)print(theInt.memory)
In Xcode, hold down the Option key theInt
to check the type of it you will find his Swift type is UnsafeMutablePointer<Int32>
. This is a pointer to the type, not the same as the Int
Int
type, it is just a pointer to it.
If we run this program and execute this Swift code, we will find a theInt
memory address like 0x00007f8bdb508ef8 in the command line, then we will see the memory
value of the member variable output 23. The memory that the access pointer points to usually returns the object to which it is pointing, in this case the original 32 bits int
(in Swift Int32
)
Now let the Objective-c class support count
the set value.
@interface pointerbridge : nsobject { intCount;} - (int*) getcountptr;-(void) SetCount: (int) Newcount;@end @implementation pointerbridge -(instancetype) init { Self= [SuperINIT];if( Self) {count = at; }return Self;} - (int*) Getcountptr {return&count;} - (void) SetCount: (int) Newcount {count = Newcount;}@end
We can call setCount()
the method to modify count
the value. Because theInt
it is a pointer, it is updated by the setCount
modification count
theInt.memory
. Do not forget that the memory address is not changed, the change is the value.
In other words, the following code prints the number 23 on the command line, and then prints the number 1000.
let bridge = PointerBridge()let theInt = bridge.getCountPtr()print(theInt.memory// 23bridge.setCount(1000)print(theInt.memory// 1000
If you want to avoid writing every time .memory
, there is a shortcut to .memory
assigning a variable:
let bridge = PointerBridge()let theInt = bridge.getCountPtr()let// 23
As before, the command line outputs 23. However, if we call the setCount()
method modified value as before count
, the problem arises:
let bridge = PointerBridge()let theInt = bridge.getCountPtr()let// 23bridge.setCount(1000// 23
The problem occurs because of a value that countVal
is assigned to it. The value is 23 when the value is assigned, so countVal
it has its own memory address, which permanently preserves the value of 23, so it has lost the pointer's characteristics. countVal
now it's just a normal Int32
type.
Create a C pointer in Swift
What if we want to do the opposite of the above? Instead Int
of using a type to count
assign a value, pass in a pointer?
We assume that there is one of the following methods in the OBJECTIVE-C code:
- (void) setCountPtr:(int *)newCountPtr { count = *newCountPtr;}
This is a very good way to do this, but it is to newCountPtr
reassign the value to count, but in Swift development you do encounter scenarios where you need to pass in pointers. This is done in a way that shows you how to create a pointer type in Swift and then pass in to the Objective-c method.
You might simply think that you can pass in a value as long as you use a reference operator like & Int
, just as you did in C. In objective-c you can write this:
int500;[self setCountPtr:&mcount];
This code can successfully count
update the value to 500. In Swift, however, you will find it more complex (and more verbose) through auto-completion. It needs to pass UnsafeMutablePointer<Int32>
in a variable of a type newCountPtr
.
I know this type is disgusting, and it looks really complicated. But, in fact, it's quite simple, especially if you know the pointers in Obj-c. If you want to create an object of a UnsafeMutablePointer<Int32>
type, we only need to call the constructor method, the only parameter that needs to be passed in is the size of the pointer (you should know that C's pointer is not a storage type, so it does not store the size of the information)
let bridge = PointerBridge()let theInt = bridge.getCountPtr()print(theInt.memory// 23let newIntPtr = UnsafeMutablePointer<Int32>.alloc(1)newIntPtr.memory100bridge.setCountPtr(newIntPtr)print(theInt.memory// 100
The only parameter that needs to be UnsafeMutablePointer<Int32>
passed to the constructor is the number of objects that need to allocate space, so we pass in 1, because we only need one Int32
object. Then we memory
can assign values to our new pointers simply by turning back on what we did before. In the end, we just need to pass the simple drip newIntPtr
into the setCountrPtr
method, then print out the value of the previous theInt
pointer, and we'll see that its value has been updated to 100.
Summarize
UnsafeMutablePointer<T>
The type of sibling type is UnsafePointer<T>
fundamentally just an abstraction of the C pointer. You can think of them as an optional type of Swift, which is easier to understand. Instead of being directly equal to an exact value, they do a layer of abstraction over an exact value. Their type is generic, which allows them to use other values, not just Int32
. For example, if you need to pass in an Float
object, you may need to UnsafeMutablePointer<Float>
.
The point is: you're not putting a Int
strong turn UnsafeMutablePointer<Int>
because the pointer is not simply a Int
value. So, if you need to create a new object, you need to call the constructor method UnsafeMutablePointer<Int>(count: Int)
.
After this article we will continue to delve into some of the details of the function pointers, and then learn how to leverage the advantages of these features to better interact with the C and Objective-c APIs. Be sure to sign up for our Newsletter so you don't miss out on these wonderful content!
Talking about the objective-c hands and Swift2