Swift C callback - takeUnretainedValue or takeRetainedValue for Swift class pointer - ios

I have several UIView or UITableViewCell. Inside I have C callback, for example:
CCallback(bridge(self),
{(observer, data) -> Void in
let mySelf = Unmanaged<DetailedView>.fromOpaque(observer!).takeRetainedValue()
mySelf.fillLoadedData(data: data)
});
Somewhere else
func bridge<T : AnyObject>(_ obj : T) -> UnsafeMutableRawPointer {
return UnsafeMutableRawPointer(Unmanaged.passUnretained(obj).toOpaque())
}
In C:
void CCalback(void * classPtr, void(*callback)(void *, MyData)){
//fill data
callback(classPtr, data)
}
Should I use takeUnretainedValue or takeRetainedValue in closure? As far as I understand this, retained will increase objects reference count, so it wont be auto-destructed? Otherwise, if I use takeUnretainedValue, if self is auto-released, this will crash, so using takeRetainedValue will prevent it. Am I correct?

An object pointer can be converted to a Unsafe(Mutable)RawPointer (the Swift
equivalent of the C void *) with or without retaining the object:
let ptr = UnsafeMutableRawPointer(Unmanaged.passUnretained(obj).toOpaque())
// Does not retain `obj`
let ptr = UnsafeMutableRawPointer(Unmanaged.passRetained(obj).toOpaque())
// Retains `obj`
The conversion back to an object pointer (often done in a callback
function called from C) can be with or without consuming a retain:
let obj = Unmanaged<T>.fromOpaque(ptr).takeUnretainedValue()
// Does not consume a retain
let obj = Unmanaged<T>.fromOpaque(ptr).takeRetainedValue()
// Consumes a retain
If the lifetime of obj is guaranteed while the callback is active
then the easiest way is to use the "unretained" conversions in both directions. You are responsible for retaining obj while the
callback is active, e.g. by unregistering the callback before obj
is deinitialized.
The alternative is to use passRetained() to convert obj to
a pointer. This retains the object and therefore keeps it "alive".
The callback can still use the "unretained" conversion to convert
the pointer to an object pointer, without decreasing the retain count.
But there must be exactly one takeRetainedValue() call to consume the
retain. After that, the object can be destroyed if there are no
other references to it.
More generally, each call to passRetained(obj) increases the retain
count and each call to takeRetainedValue() decreases it, so they must be properly balanced.

Related

Objective-C: initialization of blocks stored in collections

I read this article : Storing Blocks in an Array and want to clarify some moments.
Consider next code:
NSMutableArray* storage1;
NSMutableArray* storage2;
-(id)init{
self=[super init];
if(self){
storage1=[NSMutableArray new];
storage2=[NSMutableArray new];
}
return self;
}
-(void) f1{
__block int x=1;
dispatch_block_t b0=^{
i++;
i++;
sleep_indefinitely
};
[storage1 addObject:b0];
dispatch_async(global_concurrent_thread,b0());
[storage2 addObject:[storage1 objectAtIndex:0]];
}
The question is: will storage2 contain block with updated value of i or not? Is it necessary to copy block before storing it in collection if I want to have 2 independent instances? And if it is then how the variables with __block specifier are initialized during copying?
The answers to your questions lie in understanding lifetime – every variable and object created in a program has a lifetime which determines how long the variable or object survives. The __block attribute modified the lifetime of the variable it is applied to, potentially increasing it.
To the gory details (there will be the dead carcases of variables and objects littering the answer ;-)) starting at the beginning with a variable declared within a simple function:
int answer1(void)
{
int x = 21; // variable x is created with a fixed lifetime of the end of the function
// invocation – each function invocation creates a new distinct variable x
return x * 2;
// end of the function, x dies
}
A call to answer1() returns 42. During that call a variable is created and destroyed, after the call it no longer exists. Every call to answer1() creates a new distinct variable, and then destroys it when the invocation returns.
The lifetime of standard local variables is tied to the function, method or block statement they are created in.
Dynamically created objects have lifetimes not limited by the function/method/block statement they are created it but live as long as there exists a strong reference to them.
int answer2(void)
{
NSMutableArray *x = [NSMutableArray new]; // variable x is created with a fixed lifetime
// of the end of the function
// an NSMutableArray object is created with an
// indeterminate lifetime – it will live as long
// as there exists a strong refernece to it
// a strong reference to this object is stored in x
[x addObject:#21];
return [x[0] intValue] * 2;
// end of the function, x dies
// as x contained the only strong reference to the array object
// so that object is now longer wanted and can now be culled
// – its lifetime is now over as well
}
A call to answer2() also returns 42. Important: the array object created during the call has died not because the call has returned, the reason for variable x's demise, but because there is no longer any strong reference to it stored anywhere – unwanted it is culled.
Now let's look at blocks. On creation a block object contains copies of the values in any local variables it references:
typedef int (^IntBlock)(void); // for convenience
int answer3(void)
{
int x = 20; // variable x is created with a fixed lifetime of the end of the function
IntBlock b1 = ^{ return x; }; // variable b1 is created with a fixed lifetime of the end
// of the function
// a block object is created with an indeterminate lifetime
// and a strong reference to it is stored in b1
// the block object contains a copy of the *value* in x,
// i.e. 20
x += 2;
IntBlock b2 = ^{ return x; }; // variable b2 is created with a fixed lifetime of the end
// of the function
// a block object is created with an indeterminate lifetime
// and a strong reference to it is stored in b1
// the block object contains a copy of the *value* in x,
// i.e. 22
return b1() + b2();
// end of function
// x, b1 and b2 all die
// as b1 & b2 contained the only strong references to the two block objects
// they can now be culled – their lifetimes are over
}
A call to answer3() returns 42 (what a surprise ;-)). During the invocation of answer3() two distinct blocks are created and though the code bodies are the same they contain different values for x.
And finally we come to __block, the lifetime enhancing attribute for local variables, any local variable blessed with this attribute at birth is not consigned to die at the end of its creating function/method/block statement:
typedef void (^VoidBlock)(void);
IntBlock answer4(void)
{
__block int x = 42; // variable x is created with a lifetime the longer of:
// * the lifetime of the current invocation of answer4()
// * the lifetime of the longest living block which
// uses x
VoidBlock b1 = ^{ x = x / 2; }; // variable b1 is created with a fixed lifetime of the end
// of the function
// a block object is created with an indeterminate lifetime
// and a strong reference to it is stored in b1
// the block object contains a reference to the *variable* in x
IntBlock b2 = ^{ return x * 2; }; // variable b2 is created with a fixed lifetime of the end
// of the function
// a block object is created with an indeterminate lifetime
// and a strong reference to it is stored in b1
// the block object contains a reference to the *variable* in x
b1(); // call b1(), alters the value in x
return b2; // return a reference to the second block
// end of function
// b1 dies
// as b1 contained the only strong reference to the first block it can now be culled
// b2 also dies
// however a reference to the block it referenced is returned by the function, so
// that block lives
// the returned block references x so it to lives
}
void test4(void)
{
IntBlock b1 = answer4(); // a reference to a block is returned by answer4() and stored in b1
NSLog(#"The answer is %d", b1()); // outputs 42
// end of function
// b1 dies
// as b1 contained the onlyt surviving reference to the block returned by answer4()
// that block may now be culled
// as that block contains the only surviving reference to the variable x
// that variable may now be culled
}
A call to test4() outputs The answer is 42. Note how there is only one x shared by both b1 & b2.
Further note how the lifetime of local variable x is extended past the invocation of answer4() as it is captured by the block object that is returned. However once the block object's time is up x is culled – like an object its lifetime is dependent on something holding an interest in it.
Is it a coincidence that the conditions on the lifetime of x are rather similar to that on an object? No, the next example is effectively (i.e. precise details will differ, the visible behaviour is the same) how the compiler handles answer4():
#interface LifetimeExtenderObject5 : NSObject
#property int x;
#end
#implementation LifetimeExtenderObject5
#end
IntBlock answer5(void)
{
LifetimeExtenderObject5 *leo = [LifetimeExtenderObject5 new]; // variable leo is created with a lifetime of
// the end of the function
// a LifetimeExtenderObject5 is created with
// an indeterminate lifetime and a reference
// to it stored in leo
leo.x = 42;
VoidBlock b1 = ^{ leo.x = leo.x / 2; }; // variable b1 is created with a fixed lifetime of the end
// of the function
// a block object is created with an indeterminate lifetime
// and a strong reference to it is stored in b1
// the block object contains a copy of the *value* in leo
// this value is a strong reference to the created
// LifetimeExtenderObject5, so now there are two strong
// references to that object
IntBlock b2 = ^{ return leo.x * 2; }; // variable b2 is created with a fixed lifetime of the end
// of the function
// a block object is created with an indeterminate lifetime
// and a strong reference to it is stored in b1
// the block object contains a copy of the *value* in leo
// this value is a strong reference to the created
// LifetimeExtenderObject5, so now there are three strong
// references to that object
b1(); // call b1(), alters the value in x
return b2; // return a reference to the second block
// end of function
// leo dies, but the LifetimeExtenderObject5 object it references has other strong
// references so it lives
// b1 dies
// as b1 contained the only strong reference to the first block it can now be culled
// that block contained a string reference to created LifetimeExtenderObject5 object,
// but there are still remaining strong references to that object so it lives
// b2 also dies
// however a reference to the block it referenced is returned by the function, so
// that block lives
// that block contains a strong reference, the last one, to the created
// LifetimeExtenderObject5 object, so it still lives.
}
void test5(void)
{
IntBlock b1 = answer5(); // a reference to a block is returned by answer5() and stored in b1
NSLog(#"The answer is %d", b1()); // outputs 42
// end of function
// b1 dies
// as b1 contained the only surviving reference to the block returned by answer5()
// that block may now be culled
// as that block contains the only surviving reference to the created
// LifetimeExtenderObject5 object that object may now be culled
}
You asked:
Is it necessary to copy block before storing it in collection if I want to have 2 independent instances?
The above hopefully tells you that copying won't get you two independent instances of the captured __block variable. For that you need distinct __block variables to capture, which you get from distinct invocations of the function they are declared in. Every call to answer4() above returns a block which has captured a distinct/"independent instance" of the __block attributed variable x.
HTH more than it confuses!
First, in your code there is only one block instance created per call of f1, as there is only one ^{ } expression which is only run once. Even if there were multiple blocks, created in a particular call of f1, they would reference the same x variable, since it is a __block variable, so it is captured by reference. Also, copying a block does not create multiple instances of the block -- it simply moves the block from stack to the heap if it is not already on the heap.
It is necessary to copy the block before storing it in the collection, not because it will create multiple instances of the block (it doesn't), but because a block by default starts out on the stack as an optimization. If you will be storing it in a place that will outlive the scope where the block was created, you must "copy" the block which moves it from the stack to the heap (if it isn't there already). (The collection will "retain" the object that it needs to store, but retaining a block doesn't move it from the stack to the heap.) However, recent versions of the Clang compiler, when compiling in ARC, will implicitly add a copy when you pass a variable of block type into a function parameter of non-block object type (e.g. here, -[NSMutableArray addObject:], which takes type id), so you don't have to do it yourself.
First, The block store in both storage1 and storage2 is same block instance. Then, block store in storage2 can update i variable.
Second, If you want to have 2 independent block instances. You must call Block_copy function.
Third, When you copy block, variable with __block specifier is same in both block. Impossible copy variable with __block specifier.
Final, If you copy block also, 2 block will can update variable i.
According Apple document: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Blocks/Articles/bxVariables.html#//apple_ref/doc/uid/TP40007502-CH6-SW6
__block variables live in storage that is shared between the lexical scope of the variable and all blocks and block copies declared or created within the variable’s lexical scope. Thus, the storage will survive the destruction of the stack frame if any copies of the blocks declared within the frame survive beyond the end of the frame (for example, by being enqueued somewhere for later execution). Multiple blocks in a given lexical scope can simultaneously use a shared variable.

Converting Objective-C malloc to Swift

I am working on a project that was written in Objective-C and needs to be updated to Swift. We use a C file for transferring data.
Here is the code I was given in Objective-C:
- (NSData *)prepareEndPacket {
UInt8 *buff_data;
buff_data = (uint8_t *)malloc(sizeof(uint8_t)*(PACKET_SIZE+5));
// Call to C File
PrepareEndPacket(buff_data);
NSData *data_first = [NSData dataWithBytes:buff_data length:sizeof(uint8_t)*(PACKET_SIZE+5)];
return data_first;
}
In the C .h file I have this for reference:
#define PACKET_SIZE ((uint32_t)128)
I can not seem to find a good way of converting this to Swift. Any help would be appreciated.
malloc and free actually work fine in Swift; however, the UnsafeMutablePointer API is more "native". I'd probably use Data's bytesNoCopy for better performance. If you want, you can use Data(bytes:count:), but that will make a copy of the data (and then you need to make sure to deallocate the pointer after making the copy, or you'll leak memory, which is actually a problem in the Objective-C code above since it fails to free the buffer).
So, something like:
func prepareEndPacket() -> Data {
let count = PACKET_SIZE + 5
let buf = UnsafeMutablePointer<UInt8>.allocate(capacity: count)
PrepareEndPacket(buf)
return Data(bytesNoCopy: buf, count: count, deallocator: .custom { ptr, _ in
ptr.deallocate()
})
}
By using bytesNoCopy, the Data object returned is basically a wrapper around the original pointer, which will be freed by the deallocator when the Data object is destroyed.
Alternatively, you can create the Data object from scratch and get a pointer to its contents to pass to PrepareEndPacket():
func prepareEndPacket() -> Data {
var data = Data(count: PACKET_SIZE + 5)
data.withUnsafeMutableBytes { (ptr: UnsafeMutablePointer<UInt8>) in
PrepareEndPacket(ptr)
}
return data
}
This is slightly less efficient, since the Data(count:) initializer will initialize all the Data's bytes to zero (similar to using calloc instead of malloc), but in many cases, that may not make enough of a difference to matter.

Why, Sending nil as parameters from Objc C to swift class initializer, replaces nil parameters with new objects

I created this Swift class:
#objc public class Tester: NSObject {
private var name: String
private var user: Users
init(string:String, user: Users) {
print(user.empId)
print(user.name)
self.user = user
self.name = string
super.init()
}
}
I call the initializer from Obj C like this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
NSString * nilString = nil;
Users * nilUser = nil;
Tester * test = [[Tester alloc] initWithString:nilString user:nilUser];
return YES;
}
Here I pass nil for the parameters to the Swift initializer. Ideally I expect this to crash as the initializer only accepts non-nil values.
But what actually happens is, when the execution point reaches inside the initializer, new parameter objects are created:
The nil string becomes "" and the User variable that was nil is now pointing to an object.
But for a property like this
#property(nonatomic,strong) SomeClass * object;
where
object = nil;
When I call this object from swift,
let x = object.someGetter;
This crashes.
At one point, If I pass nil to some non null, it works and at another point, it crashes. Why does this weird behavior exist? If for some reasons, my parameters are nil, and passed to nonnull, I would like this to crash. So that I can fix things.
EDIT: This became so unexpected, further trying to play with this code.
The string parameter was actually as string, but the User shows uninitialized, hence manipulations on string worked well, but the user object, took the changes but did not showed them back.
So there are three questions:
first, why does accessing the user properties not crash,
second, why is there an empty string instead of a nil one,
third, why does assigning a property (of a custom class) crash
I'll answer all of them :-)
1. Accessing the Users properties
Swift uses Objective C messaging when accessing the properties of the Users class, (I assume - Users is an ObjC-Class as seen in the debugger output; base class NSObject).
In the disassembly view, one can see this:
0x1000018be <+78>: movq 0x3e6e2b(%rip), %rsi ; "empId"
....
0x1000018d7 <+103>: callq 0x100361b10 ; symbol stub for: objc_msgSend
Since objc_msgSend supports nil messaging, the call does not fail.
2. Empty String magic
When calling the Swift initializer from Objective C, the bridging code creates the following:
0x100001f45 <+53>: callq 0x100021f50
; static (extension in Foundation):
;Swift.String._unconditionallyBridgeFromObjectiveC (Swift.Optional<__ObjC.NSString>) -> Swift.String
....
0x100001f5b <+75>: callq 0x100001870
; TestCalling.Tester.init (string : Swift.String, user : __ObjC.ObjCUser) -> TestCalling.Tester at SwiftClass.swift:14
The interesting part here is the _unconditionallyBridgeFromObjectiveC call. This will internally call the Swift.String function _cocoaStringToSwiftString_NonASCII, and checking the source code (here, line 48), you can see the following:
#inline(never) #_semantics("stdlib_binary_only") // Hide the CF dependency
func _cocoaStringToSwiftString_NonASCII(
_ source: _CocoaString
) -> String {
let cfImmutableValue = _stdlib_binary_CFStringCreateCopy(source)
let length = _stdlib_binary_CFStringGetLength(cfImmutableValue)
let start = _stdlib_binary_CFStringGetCharactersPtr(cfImmutableValue)
return String(_StringCore(
baseAddress: start,
count: length,
elementShift: 1,
hasCocoaBuffer: true,
owner: unsafeBitCast(cfImmutableValue, to: Optional<AnyObject>.self)))
}
The function always returns a new Swift.String object, in our case an empty one! So, again no crash.
3. Property access
When accessing a custom property, e.g. assigning it to a variable:
let x:SomeClass = object.someGetter;
the following happens:
The return value of someGetter will be retained (objc_retainAutoreleasedReturnValue) -- this does not crash
The returned object will be implicitly unwrapped -- which then crashes
If x were a weak property, or an optional, the code wouldn't crash. Even when using type inference, it does not crash (on my machine, swift 4):
let x = object.someGetter;
This is, because the inferred type of x is an optional SomeClass? unless the property itself is declared as nonnull:
#property(nonatomic,strong, nonnull) SomeClass * object;
When you say the string is "" and the user is an object, it looks like you're just relying on the debugger's variable view for this, correct? Because the console output clearly shows nil twice.
What's happening here is the generated code for the initializer doesn't actually do anything that would crash if the values are nil. Semantically speaking, yes, it's invalid, but the actual machine code isn't doing something that relies on the non-nil assumption. The calls to print() work because, I assume, the code that converts the arguments into Any existentials happens to work even though the values are unexpectedly nil, and produce a nil Any.
As for the debugger view, it's a debugger, it's just doing the best it can to interpret the variables, but it's not actually running the Swift standard library. I'm not entirely sure why the string variable is showing up as "", I guess because it's always showing a string representation and it determines that it has no data (and a string with no data is ""). As for user, it actually shows it as 0x0000000000000000 which is correct, that means it's the null pointer (i.e. nil).
And then finally, let x = object.someGetter does crash, because the resulting code depends on the value being non-nil (specifically, it's presumably calling swift_retain() or swift_unknownRetain() on the value, which requires the argument to be non-nil as it dereferences the pointer).

Why doesn't referencing outside of a function create retain cycle?

Sorry, but I know this is a really dumb question, and I already kind of 'know' the answer, but I need someone to clearly explain to me WHY the answer is what it is.
Lately, I've become a bit obsessed/paranoid about retain cycles and memory leaks in my code, after going through some nightmarish debugging with various memory issues, so in the future I want to nip them in the bud. But after reading and learning a lot about ARC and retain cycles in Swift, although it makes sense, I still don't really have enough of an "intuitive" or natural feel for it, to feel confident that I could spot one, or the lack of one, as I'm coding. So I'm starting to become a little paranoid that I'm creating retain cycles with even basic stuff without realizing it.
So, with that in mind, why doesn't any ordinary function that uses a variable declared outside of it create a retain cycle? For example:
class someClass {
let a = "I'm letter a"
let moreLetters = addLetters()
func addLetters () -> String {
let newString = a + "bcdefg"
return newString
}
}
In this case, self.moreLetters references the function addLetters, and then the constant self.a is references from within the function addLetters. So would this create a retain cycle if I don't capture weak/unowned self? It seems absurd to me that something this simple would cause a problem...or is it? What about in a nested function, like this:
func someFunction () -> String {
let a = "I'm letter a"
func addLetters () -> String {
let newString = a + "bcdefg"
return newString
}
let moreLetters = addLetters()
return moreLetters
}
Would that also create a retain cycle? (Yeah I know this is a convoluted way of performing a simple task; I'm just using this code as an example to make my point).
Have I become super-paranoid and am severely overthinking things?
First, you need to understand how a basic retain cycle is formed. A retain cycle is formed when an object A refers to an object B strongly and at the same time. object B refers to object A strongly as well.
Let's look at your first bit of code.
class someClass {
let a = "I'm letter a"
let moreLetters = addLetters()
func addLetters () -> String {
let newString = a + "bcdefg"
return newString
}
}
Actually, a class by itself can never create retain cycles, so let's add some code to create an object:
var obj = someClass()
First, a is initialized to "I'm letter a". After that, moreLetters is initialized by calling the method addLetters. After the method returns, moreLetters is initialized to "I'm letter abcdefg". So far so good.
Now we set obj to nil:
obj = nil
If a retain cycle were formed, obj would not be deinitialized. However, in actuality, obj is deinitialized because nothing holds a strong reference to obj!
"Wait a minute!" you say, "But the method addLetters still refers to someClass because it has a in it!" Well, in fact, addLetters has already returned! Therefore, everything in it doesn't matter anymore! In addition, addLetters belongs to obj, which you have already set to nil!
Now let's look at your second code:
func someFunction () -> String {
let a = "I'm letter a"
func addLetters () -> String {
let newString = a + "bcdefg"
return newString
}
let moreLetters = addLetters()
return moreLetters
}
A retain cycle does not form because there isn't a even a reference type! There is no objects to be created. All you did in the second code is playing with strings, which are value types. Even if there were a class, a retain cycle would not form because as I said, when you set obj to nil, all the methods in it "disappear" because methods belong to objects.
What about those closures where I must write [weak self] or a retain cycle forms?
Those closures are escaping closures. Normal closures are deinitialized after they return. However, escaping closures are retained by some object so they are not deinitialized immediately. For more info, see Escaping Closures in Swift

Passing an object around increases retain count

iOS, transitioning to ARC. I've observed a curious behavior regarding CF/NS bridging. In the following scenario:
CFStringRef cfs = ComesFromSomewhere();
NSString *ns = (__bridge NSString*)cfs;
the retain count of the string object is 2 at the end. However, in the following:
NSString *ToNS(CFStringRef cfs)
{
return (__bridge NSString*)cfs;
}
CFStringRef cfs = ComesFromSomewhere();
NSString *ns = ToNS(cfs);
the retain count is 3 at the end. What's going on, please? Who holds the extra reference? Is the object being added to the autorelease pool by the mere act of passing it around?
Preemptive response to "don't worry, ARC just works": I'm mixing Core Foundation with Cocoa here, no way around it. This is leak prone. Without the ability to account for the retain counts explicitly, I'm flying blind.
EDIT: it's an artifact of the debug build. In the release build, the retain count under the latter scenario is still 2.
There's a tangible difference between a fragment that leaves large autoreleased objects around and one that doesn't; you don't want the former in a big loop without a pool in the loop body. Helps to know it's an artifact of zero optimization, but still, not cool.
CFStringRef cfs = ComesFromSomewhere();
// retainCount -> 1
NSString *ns = ToNS(cfs);
// ToNS(cfs)
//
// ToNS is not object creating method,
// thus the returned object was automatically autoreleased
// retainCount += 1
// NSString *ns
//
// It's __strong variable, ns variable has an ownership of the object
// retainCount += 1
// retainCount -> 3
The definition of object creating method is a method whose name begins with “alloc”, “new”, “copy”, or “mutableCopy”, of a Objective-C class. See Basic Memory Management Rules - You own any object you create.
In the release build, the retain count under the latter scenario is still 2.
Also compiler can omit to send autorelease message to object if it's eligible.
EDITED
You can use C++ reference to avoid autorelease.
void ToNS(CFStringRef cfs, NSString __strong *& ns)
{
ns = (__bridge NSString*)cfs;
}
NSString *nsstr;
ToNS(cfstr, nsstr);
// retainCount -> 2
EDITTED
NS_RETURNS_RETAINED NSString *ToNS(CFStringRef cfs)
{
return (__bridge NSString*)cfs;
}
NS_RETURNS_RETAINED makes the framework treat the function as an object creating one (which it really is). Cocoa has a name convention that lets you designate a method as an object creator, but the convention only applies to Objective C class methods, not to C style functions and not to C++ class member functions.

Resources