Using C++11 lambda functions in ARC ObjectiveC++ - how to do it properly? - objective-c

I have an ObjectiveC++ project. In the ObjectiveC context I am using ARC and iPhoneSDK 6. In C++ I am using a C++11 compiler.
Lambda functions in C++11 are capturing variables with references. This concept is not really supported by ObjectiveC and by "try and error" I came up with the following solution. Are there any pitfalls I am not aware of?
Is there a better solution to this problem?
typedef std::function<void ()> MyLambdaType;
...
// m_myView will not go away. ARC managed.
UIView * __strong m_myView;
...
// In Objective C context I create a lambda function that calls my Objective C object
UIView &myViewReference = *m_myView;
MyLambdaType myLambda = [&myViewReference]() {
UIView *myViewBlockScope = &myViewReference;
// Do something with `myViewBlockScope`
}
..
// In C++11 context I call this lambda function
myLambda();

The straightforward thing to do would be to let the lambda capture the object pointer variable m_myView (I am assuming from your snippet that this is a local variable), and use it normally inside the lambda:
MyLambdaType myLambda = [m_myView]() {
// Do something with `m_myView`
}
The only concern would be the memory management of m_myView. To be generally correct, the lambda needs to retain m_myView when it is created, and release it when it is destroyed (just like blocks do; because the lambda could be used in a scope where m_myView does not exist).
Reading through the ARC docs, I don't see this situation mentioned specifically, but I believe that it should handle it properly, because (1) captured variables of a C++11 lambda are stored as fields of an anonymous class, which are initialized to the captured value when the lambda is constructed, and (2) ARC properly handles the retaining and releasing of Objective-C object fields of C++ classes on construction and destruction. Unless it says something specifically about lambdas to the contrary, or there's a compiler bug, I see no reason why it should not work.

Related

Swift / Objective-C integration w.r.t. ARC

I'm having trouble with the integration of Objective-C and Swift. The Objective-C code uses MRC (not ARC). To boil down the issue to a simple example, imagine that I have an objective-C object that owns lots of other objects embedded in its state. It provides methods to return pointers to objects it owns. Since it does not relinquish ownership, all of these objects do not see retain or autorelease messages when they are being returned.
The flow of control takes me through code in this order
A (objective-C) calls B (Closure in Swift) and B calls C (method in Objective-C)
The sequence of calls is supposed to get a value (pointer to object) from the call to C.
Imagine that the big container class has a method (C above)
-(id)getObject:(NSUInteger)identifier
The method has been tagged for swift with:
-(__unsafe_unretained id)getObject:(NSUInteger)identifier
to indicate that the object returned should not be subjected to ARC (at least, that was my hope... It does not seem to be the case).
Now, I write a closure in swift as follows (I simplified to keep the essence) (That's B in the example):
{ k -> container.getObject(k) }
And that closure is passed to Objective-C code (A in the example) and is being called from objective-C. What I was hoping for is: no ARC "interference". But that's not the case! If I rewrite the swift closure to:
{ k -> unowned let rv = container.getObject(k); return rv}
Things are a little better (retain/release calls originating from swift code disappear), but I still get into trouble, because it seems that the compiler creates another Objective-C Block to bridge with Swift closures.
See the fragment below (lifted from lldb backtrace)
#0 0x0000000100159210 in partial apply forwarder for queensNaiveSwift.(closure #1).(closure #4) ()
#1 0x000000010015b627 in reabstraction thunk helper from #callee_owned () -> (#owned ObjectiveC.ORIntVar) to #callee_unowned #objc_block () -> (#autoreleased ObjectiveC.ORIntVar) ()
There is this "Reabstraction thunk helper" which (as I understand it) is a compiler generated objective-C block that wraps the Swift closure. As you see, its 'type' betrays the fact that the return value (type ORIntVar in reality) is #autoreleased. Looking at the assembly confirms that there is a call to autorelease. But the entire thing was written to avoid ARC. Bottom line, the thunk helper is sending my object an autorelease. That puts the object in a global auto-release pool (which defeats the purpose and delays the release). Adding a temporary autoreleasepool is not the solution here. I simply do not wish to receive retain/release/autorelease.
So... How do I tell the Swift compiler to not generate auto-release in its thunks? The value coming back is __unretained_unsafe (and unowned in Swift). Why does the thunk feel compelled to do anything with this pointer? It should be a simple pass-through, no funny business. (Also, I'd rather avoid being forced to pepper the Swift code with unowned let x = ...
Any hint/explanation is much appreciated.

How are NSBlock objects created?

I will preface this question by stating that what I am about to ask is for educational and possibly debug purposes only.
How are block objects created internally in the Objective C runtime?
I see the hierarchy of classes that all represent various block types, and the highest superclass in the hierarchy, below NSObject, is NSBlock. Dumping for class data shows that it implements the + alloc, + allocWithZone:, + copy and + copyWithZone: methods. None of the other block subclasses implement these class methods, which leads me to believe, perhaps mistakenly, that NSBlock is responsible for block handling.
But these methods seem not to be called at any point during a block's life time. I exchanged implementations with my own and put a breakpoint in each, but they never get called. Doing similar exercise with NSObject's implementations gives me exactly what I want.
So I assume blocks are implemented in a different manner? Anyone can shed a light on how this implementation works? Even if I cannot hook into the allocation and copying of blocks, I would like to understand the internal implementation.
tl;dr
The compiler directly translates block literals into structs and functions. That's why you don't see an alloc call.
discussion
While blocks are full-fledged Objective-C objects, this fact is seldom exposed in their use, making them quite funny beasts.
One first quirk is that blocks are generally created on the stack (unless they are global blocks, i.e. blocks with no reference to the surrounding context) and then moved on the heap only if needed. To this day, they are the only Objective-C objects that can be allocated on the stack.
Probably due to this weirdness in their allocation, the language designers decided to allow block creation exclusively through block literals (i.e. using the ^ operator).
In this way the compiler is in complete control of block allocation.
As explained in the clang specification, the compiler will automatically generate two structs and at least one function for each block literal it encounters:
a block literal struct
a block descriptor struct
a block invoke function
For instance for the literal
^ { printf("hello world\n"); }
on a 32-bit system the compiler will produce the following
struct __block_literal_1 {
void *isa;
int flags;
int reserved;
void (*invoke)(struct __block_literal_1 *);
struct __block_descriptor_1 *descriptor;
};
void __block_invoke_1(struct __block_literal_1 *_block) {
printf("hello world\n");
}
static struct __block_descriptor_1 {
unsigned long int reserved;
unsigned long int Block_size;
} __block_descriptor_1 = { 0, sizeof(struct __block_literal_1), __block_invoke_1 };
(by the way, that block qualifies as global block, so it will be created at a fixed location in memory)
So blocks are Objective-C objects, but in a low-level fashion: they are just structs with an isa pointer. Although from a formal point of view they are instances of a concrete subclass of NSBlock, the Objective-C API is never used for allocation, so that's why you don't see an alloc call: literals are directly translated into structs by the compiler.
As described in other answers, block objects are created directly in global storage (by the compiler) or on the stack (by the compiled code). They aren't initially created on the heap.
Block objects are similar to bridged CoreFoundation objects: the Objective-C interface is a cover for an underlying C interface. A block object's -copyWithZone: method calls the _Block_copy() function, but some code calls _Block_copy() directly. That means a breakpoint on -copyWithZone: won't catch all of the copies.
(Yes, you can use block objects in plain C code. There's a qsort_b() function and an atexit_b() function and, uh, that might be it.)
Blocks are basically compiler magic. Unlike normal objects, they are actually allocated directly on the stack — they only get placed on the heap when you copy them.
You can read Clang's block implementation specification to get a good idea what goes on behind the scenes. To my understanding, the short version is that a struct type (representing the block and its captured state) and a function (to invoke the block) are defined, and any reference to the block is replaced with a value of the struct type that has its invoke pointer set to the function that was generated and its fields filled in with the appropriate state.

Does Objective-C have closure while C does not?

I have heard that C doesn't have closure, and today I saw the use of closure in Objective-C. Is closure supported in Objective-C and not in C?
Update: thanks for all the answers. I found this guide on the web on blocks as well: http://pragmaticstudio.com/blog/2010/7/28/ios4-blocks-1
Apple added the ^ operator to add closure support. It is not tied to Objective-C however, and can be used in C and C++ as well, as long as you compile the project with Apple's brach of GCC or LLVM. This new feature is called blocks.
C has closures in the form of application-defined structures that contain both a function pointer and data pointer. The problem is just that many/most interfaces that take a callback pointer (like qsort) accept only the function pointer and not a corresponding data pointer, making it impossible to pass closures to them.
By the way, it's theoretically possible to add closure support at the library level without assistance from the compiler, i.e. create a library that would return a function pointer to a closure. However, the library code would be rather implementation/machine-dependent. It would need to allocate space for executable code and generate code to pass a fixed pointer value (saved as part of the closure object) along with other arguments to the function.

Objective-C: Is there an -invoke on blocks that takes parameters?

As you may be aware, blocks take -invoke:
void(^foo)() = ^{
NSLog(#"Do stuff");
};
[foo invoke]; // Logs 'Do stuff'
I would like to do the following:
void(^bar)(int) = ^(int k) {
NSLog(#"%d", k);
};
[bar invokeWithParameters:7]; // Want it to log '7', but no such instance method
The ordinary argument-less -invoke works on bar, but it prints a nonsense value.
I can't find a direct message of this kind I can send to a block, nor can I find the original documentation that would describe how blocks take -invoke.
Is there a list of messages accepted by blocks?
(Yes, I have tried to use class_copyMethodList to extract a list of methods from the runtime; there appear to be none.)
Edit: Yes, I'm also aware of invoking the block the usual way (bar(7);). What I'm really after is a selector for a method I can feed into library code that doesn't take blocks (per-se).
You can invoke it like a function:
bar(7);
There's even an example in the documentation that uses exactly the same signature. See Declaring and Using a Block.
The best reference on the behavior of blocks is the Block Language Specification(RTF) document. This mentions certain methods that are supported (copy, retain, etc.) but nothing about an -invoke method.
A blocks very definition is the sum total of "messages" that the block can receive, in terms of the calling parameters/ABI.
This is for a couple of reasons:
First, a block is not a function and a block pointer is not a function pointer. They cannot be used interchangeably.
Secondly, the C ABI is such that you have to have a declaration of the function begin called when the call site is being compiled if the parameters are to be encoded correctly.
The alternative is to use something like NSInvocation, which allows the arguments to be encoded individually, but even that still requires full C ABI knowledge for each individual argument.
Ultimately, if you can compile a call site that has all the parameters, be it an Objective-C method or a function call, to the fidelity necessary to make the compiler happy, you can convert that call site into a call to the block.
I.e. unless you clarify your question a bit, what you are asking for is either already supported or nigh impossible due to the vagaries of the C ABI.

Automatic variable in Objective-C

Is there a way to create a scoped variable/object with a constructor/destructor (on stack) in Objective-C or will I need to add C++ for this?
You don't need to add C/C++ anywhere, since Objective-C is already C or C++.
You can use scoped variables in any message (function) you want:
-(void) myMessage
{
// default constructor will be called
MyCPPClass myCPPClassInstance; // scoped variable of type MyCPPClass class
myCPPClassInstance.Method(); // using MyCPPClassInstance
return;
// destructor will be called after returning
}
Do note that you will have to use a file name ending with .mm in order to use C++ in Objective-C. If you just need C, then you just variables as you would in any other C function.
Is there a way to create a scoped variable/object with a constructor/destructor (on stack) in Objective-C
No.
You can created scoped C variables on the stack (obviously!) but not Objective-C classes. The concept of constructor/destructor does not exist in Objective-C.
or will I need to add C++ for this?
Yes.
But it will only work with C++ objects. I suppose you could create a C++ class to wrap an Objective-C object that allocates the Objective-C object in its constructor and releases (note not deallocs) it in the destructor. However, if you do that you might as well autorelease as soon as you alloc.