CompletionHandler call sequence - ios

I have used completionHandler in my Application as follows
fun getDetails(completionHandler: (variable: AnyObject) -() )
{
// Some work
completionHandler(variable)
}
getDetails
{
variable in
print(variable)
}
My question is what is the sequence of function calls for this execution to happen?

So the answer is when a function (say A) which has function(say B) as a parameter is called, the called function (A) execution begins. As soon as the function in parameter(function B) is called the flow goes to the point where function (A) was called. Execution of that code begins and after the execution of it, the left over part of the function(A) is executed.
In the above example when getDetails is called, the execution for that function begins but when completionHandler is called the flow jumps to the { part of getDetails, only after this is finished it comes back and starts executing after the completionHanldler() is called.

Related

How to "loosely" trigger a function?

I have the following async recursive code:
func syncData() {
dal.getList(...) { [unowned self] list, error in
if let objects = list {
if oneTime {
oneTime = false
syncOtherStuffNow()
}
syncData() // recurse until all data synced
} else if let error = error {... }
func syncOtherStuffNow() { } // with its own recursion
My understanding is that the recursion will build the call stack until all the function calls complete, at which point they will all unwind and free up the heap.
I also want to trigger another function (syncOtherStuffNow) from within the closure. But don't want to bind it to the closure with a strong reference waiting for it's return (even though it's async too).
How can I essentially trigger the syncOtherStuffNow() selector to run, and not affect the current closure with hanging on to its return call?
I thought of using Notifications, but that seems overkill given the two functions are in the same class.
Since dal.getList() takes a callback I guess it is asynchronous and so the the first syncData starts the async call and then returns immediately which lets syncData() return.
If syncOtherStuffNow() is async it will return immediately and so dataSync() will not wait on it finishing its job and so continue with its execution to the end.
You can test whether sth builds a callstack by putting a breakpoint on every recursion and look on the callstack how many calls of the same function are ontop.
What I do is recurse with asyncAfter, which unwinds the call stack.

Objective-c method to use blocks

I have a method that calls a long running process. the long running process and I use AFNetworking which itself uses blocks and returns success block and failure block. So I am trying to test my method and the tests will fail before the success block is called. I thought I would try to get my method to also use blocks. I have another method that I managed to change to use blocks but that only uses bool isFinished and the return value is void. The method I have difficult with needs to return NSDecimalNumber* and takes an NSString.
Method signature
(NSDecimalNumber*) getRate:(NSString*) rateCode;
I would like to be able to able to add a completion block with a BOOL that I set when the AFNetworking method enters the success block
I would also like to be able to call the method and within it's completion block access the NSDecimalNumber* value it returned
Possible? If so please show me how
You probably have to split it apart.
You can have a fetchRate: method that takes a completion block:
- (void)fetchRate:(NSString*)rateCode completion:(void (^)(NSDecimalNumber *))completion;
Then call like this:
void (^completion)(NSDecimalNumber *) = ^(NSDecimalNumber * rate){
// this is called when rate is returned from your webservice
}
// call fetchRate: now, results will arrive later...
[ myObj fetchRate:<rate code> completion:completion ];
// code here runs immediately; the results come back later.
-fetchRate: looks something like...
- (void)fetchRate:(NSString *)rateCode completion:(void (^)(NSDecimalNumber *))completion
{
void (^asiCompletionBlock)(/*args*/) = ^(/*...args...*/){
// called after ASI request completes
NSDecimalNumber * answer = /* get answer from ASI HTTP response */
// call our completion block that was passed in:
completion( answer );
};
// do your asi HTTP request here, pass asiCompletionBlock for completion arg
}

iOS Why wouldn't exiting a method in the main thread from a sub-thread work?

I'm initiating an asynch thread using grand central dispatch in objective-c using the following code:
dispatch_queue_t myQueue = dispatch_queue_create("My Queue",NULL);
dispatch_async(myQueue, ^{
}
For a very long time I was having trouble correctly exiting the IBAction that triggers this. I do a lot of the code in the main thread wrapped inside this GCD thread using this code:
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
}
What I originally tried to do was simply put the return; statement inside this mainQueue block. After a lot of fiddling I discovered that to break out of the IBAction that contains all this the return; needs to be in the GCD queue.
Why is this? I thought that return would exit methods regardless of where it is in the program. Also, is it even possible to exit from a nested queue call like this?
A block is similar to a function. It is a different context from the code which defines it. A return statement within a block exits that block, not the method or function within which the block was defined. (If the block has a non-void return type, the return statement also gives the return value of the block.)
For example, consider:
void foo(void)
{
int (^block)(int, int) = ^int(int a, int b) { return a + b; }
printf("3 + 5 = %d\n", block(3, 5));
}
The return statement in the block does not return from foo(), it just returns from the block and gives the return value of the block. The block is like a little separate function except that its code is provided right in the middle of another function and it can capture local variables from the context of its definition.
Now, the block given to dispatch_async() does not take arguments or return a value, but the flow control of the return statement is the same. It returns from that block, not from the method or function containing the call to dispatch_async(). In particular, since dispatch_async() runs the block asynchronously, it is quite possible (even likely) that the block won't be run until well after the method or function that called dispatch_async() has already exited.

Enumerate/Iterate over an array using Blocks and know when it is completed

I'd like to iterate through an array in Swift and I need to know when the last item has been reached. I am using enumerateObjectsUsingBlock. As there is no optional completion block (like in some of the CoreAnimation methods) I assume the stop parameter signals the end point – is this correct?
itemsArray.enumerateObjectsUsingBlock {
(object, index, stop) -> Void in
self.displayedItems.addObject(object as SpecialItem)
if stop == true {
println("the end.")
}
}
stop seems to be of the type UnsafeMutablePointer. Therefore I cannot simply test it for being true/false or nil. How do I know when the enumeration is completed?
enumerateObjectsUsingBlock executes synchronously. The enumeration is finished
when the method returns.
stop is a reference to a Boolean which can be set to true to stop further processing,
for example:
itemsArray.enumerateObjectsUsingBlock {
(object, index, stop) -> Void in
// process at most 5 elements:
if index == 4 {
stop.memory = true
}
}
Testing if stop == true inside the block does not make sense.
Get the count prior to the block and then compare the index to the count to determine when you are at the last item.
If you just want to execute code after the enumeration is complete just put the code immediately following the block code. This block is not an asynchronous.
Note: Stop is a variable that can be set in the block to terminate enumeration early. See the documentation.

Objective-C: Method's return value and Completion block, how are they executed?

I make an photography app in iPhone and I have these 3 classes: ViewController, CaptureManager, and ImgProcessor.
ViewController:
-(IBAction)takePic:(id)sender{
images = [captureManager takeMultipleImagesWithCompletion:^{
//Some UI related code..
[imgProcessor process:images];
}];
}
CaptureManager:
-(NSArray *)takeMultipleImagesWithCompletion:^(void)completionHandler{
// take picture codes...
completionHandler();
return arrayOfImagesTaken;
}
So far it works as desired: imgProcessor processes the images taken by captureManager. But I don't quite get the idea how this works. Bcos I called completionHandler before I return the array of images taken. How did this code executed? Is there a better solution to this?
Thanks!
You don't need to return the value images. You can pass it as an argument for the cmpletionHandler block.
-(void)takeMultipleImagesWithCompletion:(void (^)(NSArray *images))completionHnadler{
// take picture codes...
completionHnadler(arrayOfImagesTaken);
}
You can call it like this :
-(IBAction)takePic:(id)sender{
[captureManager takeMultipleImagesWithCompletion:^(NSArray *images){
[imgProcessor process:images];
}];
}
How it works ?
Here the block is used as a callback, it defines the code to be executed when a task completes. When the takeMultipleImagesWithCompletion is finished running, the block completionHnadler will be called.
Since your takeMultipleImagesWithCompletion executes the completion block synchronously, it doesn't need to take a completion block. It can just return the arrayOfImagesTaken and the caller can do whatever it wants with it.

Resources