Blocks and messaging - ios

The question here is more of an educational one. I began to think of this an hour ago while
flipping around a lego block (silly, I know).
A block is an object created on stack, from what I understand.
Let say A is an object, which means we can do:
[A message];
Based on that, if a block is an object, we could also do:
[block message];
Am I correct?
And when the runtime sees that, it would call:
objc_msgSend(block, #selector(message), nil);
So my question is, how can we send a block a message?
And if that is possible, I would imagine that it would also be possible to send a block a message with the arguments being blocks as well?
And, if we could call a block by doing:
block();
Does that mean we could even make a block as a message (SEL) as well, because blocks have the signature void (^)(void) which resembles that of a method?
Because if it would be possible, then the following would really surprise me:
objc_msgSend(block, #selector(block), block);
or:
objc_msgSend(block1, #selector(block2), block3);
I hope my imagination is not running a bit wild and that my understanding is not off here (correct me, if it is).

Blocks are objects only for the purposes of storage and referencing. By making them objects, blocks can be retain/release'd and can, therefore, be shoved into arrays or other collection classes. They also respond to copy.
That's about it. Even that a block starts on the stack is largely a compiler implementation detail.
When a block's code is invoked, that is not done through objc_msgSend(). If you were to read the source for the block runtime and the llvm compiler, then you'd find that:
a block is really a C structure that contains a description of the data that has been captured (so it can be cleaned up) and a pointer to a function -- to a chunk of code -- that is the executable portion of the block
the block function is a standard C function where the first argument must always be a reference to the block. The rest of the argument list is arbitrary and works just like any old C function or Objective-C method.
So, your manual calls to objc_msgSend() treat the block like any other random ObjC object and, thus, won't call the code in the block, nor, if it did (and there is SPI that can do this from a method... but, don't use it) could it pass an argument list that was fully controllable.
One aside, though of relevance.
imp_implementationWithBlock() takes a block reference and returns an IMP that can be plugged into an Objective-C class (see class_addMethod()) such that when the method is invoked, the block is called.
The implementation of imp_implementationWithBlock() takes advantage of the layout of the call site of an objective-c method vs. a block. A block is always:
blockFunc(blockRef, ...)
And an ObjC method is always:
methodFunc(selfRef, SEL, ...)
Because we want the imp_implementationWithBlock() block to always take the target object to the method as the first block parameter (i.e. the self), imp_implementationWithBlock() returns a trampoline function that when called (via objc_msgSend()):
- slides the self reference into the slot for the selector (i.e. arg 0 -> arg 1)
- finds the implementing block puts the pointer to that block into arg 0
- JMPs to the block's implementation pointer
The finds the implementing block bit is kinda interesting, but irrelevant to this question (hell, the imp_implementationWithBlock() is a bit irrelevant, too, but may be of interest).
Thanks for response. It's definitely an eye opener. The part about
blocks calling is not done thru objc_msgSend() tells me that it is
because blocks are not part of the normal object-hierachry (but coda's
mentioning of NSBlock seems to refute what I understand so far,
because NSBlock would make it part of the object-hierachy). Feel free
to take a stab at me, if my understanding is still off so far. I am
very interested in hearing more about the followings 1: the SPI and
the way (how) to call that method. 2: the underlying mechanisms of:
sliding the self reference into the slot. 3: finds the implementing
block and puts the pointer to that block into arg 0. If you have time
to share and write a bit more about those in detail, I am all ears; I
find this all very fascinating. Thanks very much in advance.
The blocks, themselves, are very much just a standard Objective-C object. A block instance contains a pointer to some executable code, any captured state, and some helpers used to copy said state from stack to heap (if requested) and cleanup the state on the block's destruction.
The block's executable code is not invoked like a method. A block has other methods -- retain, release, copy, etc... -- that can be invoked directly like any other method, but the executable code is not publicly one of those methods.
The SPI doesn't do anything special; it only works for blocks that take no arguments and it is nothing more than simply doing block().
If you want to know how the whole argument slide thing works (and how it enables tail calling through to the block), I'd suggest reading this or this. As well, the source for the blocks runtime, the objc runtime, and llvm are all available.
That includes the fun bit where the IMP grabs the block and shoves it into arg0.

Yes, blocks are objects. And yes, that means you can send messages to them.
But what message do you think a block responds to? We are not told of any messages that a block supports, other than the memory management messages retain, release, and copy. So if you send an arbitrary message to a block, chances are that it will throw a "does not recognize selector" exception (the same thing that would happen if you sent an arbitrary message to any object you don't know the interface of).
Invoking a block happens through a different mechanism than message sending, and is magic implemented by the compiler, and not exposed to the programmer otherwise.
Blocks and selectors are very different. (A selector is just an interned string, the string of the method name.) Blocks and IMPs (functions implementing methods) are somewhat similar. However, they are still different in that methods receive the receiver (self) and the selector called as special parameters, whereas blocks do not have them (the function implementing the block only receives the block itself as a hidden parameter, not accessible to the programmer).

Related

Significance of Target in detaching a Thread in Swift

I have recently started getting acquainted with explicit Multithreading in swift. I am trying to understand the below method to dispatch a new thread for executing a selector. while I am able to use it successfully, what I don't understand is what is the significance of target in the signature of the method below? is that argument used to hold a monitor lock for thread safety like in java ? I tried referring to the documentation with not much help. I would really appreciate if someone can help me understand what's happening under the hood here.
(void)detachNewThreadSelector:(SEL)selector
toTarget:(id)target
withObject:(id)argument;
The documentation for aTarget says:
The object that will receive the message aSelector on the new thread.
This means that the selector will be called on the object that you pass as the target. It's no different than making any other method call. You call a method on a specific instance of a class. The target is the specific instance. The selector is the method that is called on that instance.
Think of detachNewThreadSelector:toTarget:withObject: as calling the given method of the given object, with the given argument (or ignore the argument if the method has zero parameters), but call the method on a newly created thread.
For example:
[NSThread detachNewThreadSelector:#selector(expensiveComputationWithObjects:)
target:someCalculatorObject
withObject:someVeryLargeArray]
The method thus provides a very convenient way of dispatching method calls on background threads (though it doesn't allow reusing an existing thread).
Another minor disadvantage is that the methods in discussions need to have at most one parameter, though this limitation can be circumvented by having the target method receive a structure (a dictionary or another class) that holds the actual arguments.

Is a block in Objective-C always guaranteed to capture a variable?

Are there any conditions in Objective-C (Objective-C++) where the compiler can detect that a variable capture in a block is never used and thus decide to not capture the variable in the first place?
For example, assume you have an NSArray that contains a large number of items which might take a long time to deallocate. You need to access the NSArray on the main thread, but once you're done with it, you're willing to deallocate it on a background queue. The background block only needs to capture the array and then immediately deallocate. It doesn't actually have to do anything with it. Can the compiler detect this and, "erroneously", skip the block capture altogether?
Example:
// On the main thread...
NSArray *outgoingRecords = self.records;
self.records = incomingRecords;
dispatch_async(background_queue, ^{
(void)outgoingRecords;
// After this do-nothing block exits, then outgoingRecords
// should be deallocated on this background_queue.
});
Am I guaranteed that outgoingRecords will always be captured in that block and that it will always be deallocated on the background_queue?
Edit #1
I'll add a bit more context to better illustrate my issue:
I have an Objective-C++ class that contains a very large std::vector of immutable records. This could easily be 1+ million records. They are basic structs in a vector and accessed on the main thread to populate a table view. On a background thread, a different set of database records might be read into a separate vector, which could also be quite large.
Once the background read has occurred, I jump over to the main thread to swap Objective-C objects and repopulate the table.
At that point, I don't care at all about the contents of the older vector or its parent Objective-C class. There's no fancy destructors or object-graph to teardown, but deallocating hundreds of megabytes, maybe even gigabytes of memory is not instantaneous. So I'm willing to punt it off to a background_queue and have the memory deallocation occur there. In my tests, that appears to work fine and gives me a little bit more time on the main thread to do other stuff before 16ms elapses.
I'm trying to understand if I can get away with simply capturing the object in an "empty" block or if I should do some sort of no-op operation (like call count) so that the compiler cannot optimize it away somehow.
Edit #2
(I originally tried to keep the question as simple as possible, but it seems like it's more nuanced then that. Based on Ken's answer below, I'll add another scenario.)
Here's another scenario that doesn't use dispatch_queues but still uses blocks, which is the part I'm really interested in.
id<MTLCommandBuffer> commandBuffer = ...
// A custom class that manages an MTLTexture that is backed by an IOSurface.
__block MyTextureWrapper *wrapper = ...
// Issue some Metal calls that use the texture inside the wrapper.
// Wait for the buffer to complete, then release the wrapper.
[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> cb) {
wrapper = nil;
}];
In this scenario, the order of execution is guaranteed by Metal. Unlike the example above, in this scenario performance is not the issue. Rather, the IOSurface that is backing the MTLTexture is being recycled into a CVPixelBufferPool. The IOSurface is being shared between processes and, from what I can tell, MTLTexture does not appear to increase the useCount on the surface. My wrapper class does. When my wrapper class is deallocated, the useCount is decremented and the bufferPool is then free to recycling the IOSurface.
This is all working as expected but I end up with silly code like above just out of uncertainty whether I need to "use" the wrapper instance in the block to ensure it's captured or not. If the wrapper is deallocated before the completion handler runs, then the IOSurface will be recycled and the texture will get overwritten.
Edit to address question edits:
From the Clang Language Specification for Blocks:
Local automatic (stack) variables referenced within the compound
statement of a Block are imported and captured by the Block as const
copies. The capture (binding) is performed at the time of the Block
literal expression evaluation.
The compiler is not required to capture a variable if it can prove
that no references to the variable will actually be evaluated.
Programmers can force a variable to be captured by referencing it in a
statement at the beginning of the Block, like so:
(void) foo;
This matters when capturing the variable has side-effects, as it can
in Objective-C or C++.
(Emphasis added.)
Note that using this technique guarantees that the referenced object lives at least as long as the block, but does not guarantee it will be released with the block, nor by which thread.
There's no guarantee that the block submitted to the background queue will be the last code to hold a strong reference to the array (even ignoring the question of whether the block captures the variable).
First, the block may in fact run before the context which submitted it returns and releases its strong reference. That is, the code which called dispatch_async() could be swapped off the CPU and the block could run first.
But even if the block runs somewhat later than that, a reference to the array may be in an autorelease pool somewhere and not released for some time. Or there may be a strong reference someplace else that will eventually be cleared but not under you explicit control.

What is difference between function/method and block in objective c or Swift

I am learning objective c and swift. i didn't get what is difference between block and method or function in Objective c or in Swift.
int mutiplier=10;
int (^myBlock)(void)=^{
return 10 *3;
};
NSLog(#"%d",myBlock());
Or can write method/function like this
-(int)function:(int)num{
return num* 10;
}
Blockquote
Short and simple:
Block of code - just a block of code. You can declare it, define types of blocks(then make an instances), call blocks one by one, etc. Blocks can take parameters, can return something, It`s quite convenient to use them along with a Grand Central Dispatch. Blocks can declared right in the middle of the code, as an instance variable or as a property. They can also be passed as an arguments to a method/function call. After block has done its work you can call the 'completion' part to run some specific code, which is convenient in some cases. In a swift language similar to blocks (but not equal) thing is a closure. Would like to add that there is a block-based enumeration approach available in Objective-c which is almost as fast as Fast enumeration. Would recommend fast enumeration for most cases, but sometimes (rare) block enumeration is better. Other loops usually is not as fast as this two ones. One more important thing we should keep in mind is that the blocks are Objective-C objects while functions and methods are not. Blocks can capture values from the variables from the enclosing scope while to get the same values inside of a function/method you need to pass these variables as an arguments. Using blocks you can even change these variables using f.e.
__block int anInteger = 123;
syntax before the block call.
Keep in mind you avoid strong reference to a self when capturing it inside of a block to avoid retain cycles. Use weakSelf in that case.
https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/WorkingwithBlocks/WorkingwithBlocks.html
Function should have name, return something or be void.
Method is a function of a class.
Blocks are a way of wrapping up a piece of code and effectively storing it for later use. A block is commonly used in place of a call back function. Newer APIs in the iPhone SDK use blocks this way. The API will take a "block" of code that it will run on completion. And Blocks are presented in swift as a Closure.
In swift it's little tough syntax to learn closure. but trust me it's very handy way when you start to use it.
It saves you having to create your own threads and maintain the state of each thread, manage locks, setup autorelease pools etc.
Also, when used with the Grand Central Dispatch (GCD) API blocks can be run on queues and entire portions of code can be made to run asynchronously with very little effort, but still keeping the robustness that is required for multithreaded code.

Understand one edge case of block memory management in objc

the code below will crash because of EXC_BAD_ACCESS
typedef void(^myBlock)(void);
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *tmp = [self getBlockArray];
myBlock block = tmp[0];
block();
}
- (id)getBlockArray {
int val = 10;
//crash version
return [[NSArray alloc] initWithObjects:
^{NSLog(#"blk0:%d", val);},
^{NSLog(#"blk1:%d", val);}, nil];
//won't crash version
// return #[^{NSLog(#"block0: %d", val);}, ^{NSLog(#"block1: %d", val);}];
}
the code runs in iOS 9 with ARC enabled. And I was trying to figure out the reason that lead to crash.
by po tmp in lldb I found
(lldb) po tmp
<__NSArrayI 0x7fa0f1546330>(
<__NSMallocBlock__: 0x7fa0f15a0fd0>,
<__NSStackBlock__: 0x7fff524e2b60>
)
whereas in the won't crash version
(lldb) po tmp
<__NSArrayI 0x7f9db481e6a0>(
<__NSMallocBlock__: 0x7f9db27e09a0>,
<__NSMallocBlock__: 0x7f9db2718f50>
)
So the most possible reason I could come up with is when ARC release the NSStackBlock the crash happen. But why would so?
First, you need to understand that if you want to store a block past the scope where it's declared, you need to copy it and store the copy instead.
The reason for this because of an optimization where blocks which capture variables are initially located on the stack, rather than dynamically allocated like a regular object. (Let's ignore blocks which don't capture variables for the moment, since they can be implemented as a global instance.) So when you write a block literal, like foo = ^{ ...};, that's effectively like assigning to foo a pointer to a hidden local variable declared in that same scope, something like some_block_object_t hiddenVariable; foo = &hiddenVariable; This optimization reduces the number of object allocations in the many cases where a block is used synchronously and never outlives the scope where it was created.
Like a pointer to a local variable, if you bring the pointer outside the scope of the thing it pointed to, you have a dangling pointer, and dereferencing it leads to undefined behavior. Performing a copy on a block moves a stack to the heap if necessary, where it is memory-managed like all other Objective-C objects, and returns a pointer to the heap copy (and if the block is already a heap block or global block, it simply returns the same pointer).
Whether the particular compiler uses this optimization or not in a particular circumstance is an implementation detail, but you cannot assume anything about how it's implemented, so you must always copy if you store a block pointer in a place that will outlive the current scope (e.g. in a instance or global variable, or in a data structure that may outlive the scope). Even if you knew how it was implemented, and know that in a particular case copying is not necessary (e.g. it is a block that doesn't capture variables, or copying must already have been done), you should not rely on that, and you should still always copy when you store it in a place that will outlive the current scope, as good practice.
Passing a block as an argument to a function or method is somewhat complicated. If you pass a block pointer as an argument to a function parameter whose declared compile-time type is a block-pointer type, then that function would in turn be responsible for copying it if it were to outlive its scope. So in this case, you wouldn't need to worry about copying it, without needing to know what the function did.
If, on the other hand, you pass a block pointer as an argument to a function parameter whose declared compile-time type is a non-block object pointer type, then that function wouldn't be taking responsibility for any block copying, because for all it knows it's just a regular object, that just needs to be retained if stored in a place that outlives the current scope. In this case, if you think that the function may possibly store the value beyond the end of the call, you should copy the block before passing it, and pass the copy instead.
By the way, this is also true for any other case where a block-pointer type is assigned or converted to a regular object-pointer type; the block should be copied and the copy assigned, because anyone who gets the regular object-pointer value wouldn't be expected to do any block copying considerations.
ARC complicates the situation somewhat. The ARC specification specifies some situations where blocks are implicitly copied. For example, when storing to a variable of compile-time block-pointer type (or any other place where ARC requires a retain on a value of compile-time block-pointer type), ARC requires that the incoming value be copied instead of retained, so the programmer doesn't have to worry about explicitly copying blocks in those cases.
With the exception of retains done as part of initializing a
__strong parameter variable or reading a __weak variable, whenever
these semantics call for retaining a value of block-pointer type, it
has the effect of a Block_copy.
However, as an exception, the ARC specification does not guarantee that blocks only passed as arguments are copied.
The optimizer may remove such copies when it sees that the result is
used only as an argument to a call.
So whether to explicitly copy blocks passed as arguments to a function is still something the programmer has to consider.
Now, the ARC implementation in recent versions of Apple's Clang compiler has an undocumented feature where it will add implicit block copies to some of the places where blocks are passed as arguments, even though the ARC specification doesn't require it. ("undocumented" because I cannot find any Clang documentation to this effect.) In particular, it appears that it defensively always adds implicit copies when passing an expression of block-pointer type to a parameter of non-block object pointer type. In fact, as demonstrated by CRD, it also adds an implicit copy when converting from a block-pointer type to a regular object-pointer type, so this is the more general behavior (since it includes the argument passing case).
However, it appears that the current version of the Clang compiler does not add implicit copies when passing a value of block-pointer type as varargs. C varargs are not type-safe, and it is impossible for the caller to know what types the function expects. Arguably, if Apple wants to error on the side of safety, since there's no way of knowing what the function expects, they should add implicit copies always in this case too. However, since this whole thing is an undocumented feature anyway, I wouldn't say it's a bug. In my opinion, then programmer should never rely on blocks that are only passed as arguments being implicitly copied in the first place.
Short Answer:
You have found a compiler bug, possibly a re-introduced one, and you should report it at http://bugreport.apple.com.
Longer Answer:
This wasn't always a bug, it used to be a feature ;-) When Apple first introduced blocks they also introduced an optimisation in how they implemented them; however unlike normal compiler optimisations which are essentially transparent to the code they required programmers to sprinkle calls to a special function, block_copy(), in various places to make the optimisation work.
Over the years Apple removed the need for this, but only for programmers using ARC (though they could have done so for MRC users as well), and today the optimisation should be just that and programmers should no longer need to help the compiler along.
But you've just found a case where the compiler gets it wrong.
Technically you have a case a type loss, in this case where something known to be a block is passed as id - reducing the known type information, and in particular type loss involving the second or subsequent argument in a variable argument list. When you look at your array with po tmp you see the first value is correct, the compiler gets that one right despite there being type loss, but it fails on the next argument.
The literal syntax for an array does not rely on variadic functions and the code produced is correct. However initWithObjects: does, and it goes wrong.
Workaround:
If you add a cast to id to the second (and any subsequent) blocks then the compiler produces the correct code:
return [[NSArray alloc] initWithObjects:
^{NSLog(#"blk0:%d", val);},
(id)^{NSLog(#"blk1:%d", val);},
nil];
This appears to be sufficient to wake the compiler up.
HTH

Using C++-objects in Objective-C-blocks

I have a C++-object obj which I want to access within a block:
MyCppClass obj;
void(^myBlock)() = ^{
obj.test();
};
The problem here is that obj gets copied into the block, but I want to use a reference to the original object. I could use a pointer instead:
MyCppClass obj;
MyCppClass *objP = &obj;
void(^myBlock)() = ^{
objP->test();
};
But I think dereferencing pointers takes more time than using references. (Performance is critical, because in my project such a block is called for each pixel of a large image.)
How can I access the object within the block?
Dereferencing a pointer is faster than a function call or a C++ method call,which involves several pointer dereferences to look up the method in the class, and then an actual function call, which actually allocates memory on the stack, saves away some registers to RAM, and then does the reverse when it returns. So don't worry about performance here. If the profiler shows you that a single pointer de-reference causes performance issues, you have bigger problems, and you should probably drop down to hand-crafted assembler, and forget using C++ classes or blocks. Also, it's a very rare thing.
Use a pointer, or a C++ reference (the latter is the same under the hood, but it's harder to shoot yourself in the foot with it, and code stays more readable). Just keep in mind that this is only a solution if you are going to use the block in the same function as (or a function called by) the current function.
Because the C++ object is on the stack, it will go away, so if whoever you hand the block to copies it and calls it later, the pointer will be invalid. In the best case you will crash. In the worst case, the spot on the RAM chip that was used for that object is already in use for something else again, and you'll overwrite some other bit of memory, and cause a seemingly unrelated crash.
So, if you want to keep the block around, you'll have to do 'objP = new MyCppClass' to create the object, and later do 'delete objP' (maybe in the last call to the block, if you can detect that and don't need the object after that) to get rid of it.

Resources