Supposing I have a code like this:
[ApiConnection getServerTimeWithBlock:^(BOOL gotTimeResponse){
if(gotTimeResponse)
{
//we're online, got the response from time endpoint
[ApiConnection registerNewCustomerWithBlock:^(NSString* val){
if(val)
{
NSLog(#"val: %#",val);
}
else
{
NSLog(#"no val");
}
}];
}
else
{
//we're offline
}
}];
NSLog(#"TEST");
why is the last NSLog executed before the whole first block has finished execution?
Because the getServerTimeWithBlock: method is asynchronous, so it returns immediately and runs on a background thread. When that thread is complete is calls the completion block.
So, the method runs before your log, but the completion block (usually) doesn't (it might if there was an error or something like that).
Presumably getServerTimeWithBlock: is exectuted asynchronously. When supplying the block, you're telling the APIConnection object what to do when it has finished getting the server time. This will involve network fetches and reading data back, which you don't want to wait for on the main thread as this will cause your UI to freeze. Your program therefore carries on, and the block is executed whenever the fetch is complete.
Note that blocks do not imply that asynchronous or multithreaded code is in use (see NSArray's enumerateWithBlock: method, for example) but it seems very likely to be the case here.
Related
I am trying to use QThread to call a function in another thread without having the UI to freeze. I am using QT5.11.2 on both windows and linux.
Everything works fine on windows but the wait() function for QThread never returns no matter what.
I use RHEL7 on linux
Here is what I am doing:
void MainWidget::configure_click(double value)
{
QThread *myThread = QThread::create([this, value]{ Configure(value); });
dsoThread->setObjectName("My Configure Thread");
QObject::connect(myThread, &QThread::finished, [](){ qDebug()<< "Configure Thread has finished";}); // This is never printed
myThread->start();
myThread->wait(); // Never returns from this
myThread->quit();
myThread->deleteLater();
}
My Configure function prints its start and finish and both lines are being printed on run time
void MainWidget::Configure(double value)
{
qDebug() << QThread::currentThread() << " started";
// Code to execute
qDebug() << QThread::currentThread() << " finished";
}
I even read that quit() forces the thread to stop, so just for testing I tried switching quit() and wait() like so
myThread->quit();
myThread->wait(); // Never returns from this either
myThread->deleteLater();
I even tried looping the isRunning() function instead of wait() but I got the same results
while(myThread->isRunning()) // Same goes for !isFinished()
{
// Do nothing
}
It seems like no matter what the thread never knows that it was finished.
What can I do to either solve this problem or to check why this is happening?
You haven't start()ed the thread.
myThread->wait(); in gui thread waits for thread to terminate so it blocks gui thread event loop, so you lose all benifints of threading this way and might as well just do Configure(value); without threading.
Documentation says:
wait() and the sleep() functions should be unnecessary in
general, since Qt is an event-driven framework. Instead of
wait(), consider listening for the finished() signal. Instead of
the sleep() functions, consider using QTimer.
I have view models that are being stored in an array list on the application class. So their lifetime continues even if the activity gets destroyed because of rotation (however once isFinishing is true then the view model instance is removed from the list and ceases to exist).
I also have data service singletons that are used by the view models that also live indefinitely. So if I start an async call in my view model using the anko async block i.e.
async {
val data = DataService.instance.getData()
uiThread {
if (data != null) {
//do something
}
}
}
What happens if the user presses the back button before the call completes? IsFinishing will be true and my view model instance will no longer exist. Will the async call exception when it returns or will it die gracefully?
The code within uiThread call won't get executed if the underlying activity/fragment context has been garbage collected. A uiThread call within an async call will hold a WeakReference to the context, so the often encountered context memory leak won't occur. Details here.
I guess it will gracefully die. You could write a small test program in which you debug the behaviour. However, I would strongly suggest to keep a reference/pointer to the asynchronous task and kill it when you press the back button. No need to let it run in the background if you do not need the result / cannot handle the result anymore right
I have a piece of code, which is processing a queue synchronously and asynchronously. I'm using OCMock to test the thing and individually I can test both cases (synchronous and asynchronous) but when I test for both at the same time I get trouble.
To verify that the queue is processed correctly I'm passing it a mocked listener and from this listener I'm then asking if it got all the notifications propagated by the queue processor. I have two tests and in the first test (asynchronous) these expectations are met but with the second test (synchronous) I get this error:
OCMockObject[JHQueueListener] : 4 expected methods were not invoked:
startedProcessingQueue
startedToProcessQueueItem:OCMockObject[JHQueueItem]
finishedProcessingQueueItem:OCMockObject[JHQueueItem]
finishedProcessingQueue
Here's a link to the project:
https://github.com/jphollanti/queue-processor
And here's a link to the test:
https://github.com/jphollanti/queue-processor/blob/master/QueueProcessorTests/JHQueueProcessorTests.m
Issue #1: The references are fine but when it comes to the tests, threading is expected to work incorrectly. The problem here is that a new thread is started and in that new thread the status of the queue is set as in progress. But it takes longer to start up a new thread than it does for the main thread to ask for the status and this results in the fact that the queue is not (yet) in progress. Adding a delay of some 10000ms should help things a lot. Like so:
...
[queue processQueueAsynchronously:queueItems];
usleep(10000);
BOOL wentToThread = NO;
while ([queue isInProgress]) {
wentToThread = YES;
...
}
...
Also, calling dispatch_async(dispatch_queue_t queue, ^(void)block) takes a lot of time and this adds up to the "random" nature of the issues.
Issue #2: Calling dispatch_async(dispatch_get_main_queue(), ^{ ... } from the main thread causes the block to be sent to some queue which is executed at some time (don't know how it works). This is why the second test (synchronous) failed. Using something like this helps:
if ([NSThread isMainThread]) {
for (id <JHQueueListener> listener in listeners) {
[listener startedToProcessQueueItem:queueItem];
}
} else {
dispatch_async(dispatch_get_main_queue(), ^{
for (id <JHQueueListener> listener in listeners) {
[listener startedToProcessQueueItem:queueItem];
}
});
}
So I have a wrapper class that when I send it a message, it returns YES/NO based on whether the internal object RECEIVED the message. Meaning, when I send this, it doesn't actually return when the task is done. I also want to make sure that only one task is executed at a time, so I use dispatch semaphores. My wrapper class calls a delegate method to notify me that it finished processing the internal task.
dispatch_queue_t queue = dispatch_queue_create("com.test.all", 0); // private queue
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1); // one at a time
...
- (void)doStuff:(NSString *)stuff {
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_sync(queue, ^(void) {
[myWrapperObject sendRequestToInternalStuff:stuff];
}
}
...
- (void)myWrapperClassProcessingIsDone {
dispatch_semaphore_signal(semaphore);
}
This doesn't work, and it hangs. How can I implement something like this without hanging?
If you want to ensure that only one task is executed at a time, the correct approach is to execute each task on the same serial GCD queue. A serial queue always executes just one task at a time. The dispatch_queue_create function creates a serial queue when you pass 0 (or DISPATCH_QUEUE_SERIAL or NULL) as the second argument..
If anyone needs to know, there is no way to do this. The semaphore locks the thread, so you would have to have a separate spawned thread with a run-loop waiting for a variable change. I just re-worked my code to avoid semaphores.
Here is the things I need to do...
-(unsigned int)doSomething
{
msg_id++;
//something need to be done after returning
//process
return msg_id;
}
[somebody doSomething];
Now the process is like this:
somebody called doSomething
Process is executed
Msg id is returned
The flow I wanna:
somebody called doSomething
Msg id is returned
Process is executed
You can ask me to do when somebody doSomething is finished, but I can't change this part. I can only change the doSomething method. Also, some workaround suggestions is calling a delay after X seconds. But I concern the after delay X second. Because I don't know return msg_id need how many second, actually.
Any better suggestion?
CS101. return, does just that. It returns. Perhaps, you want 'process' to be something that is done in the background, or on a separate thread? You might be looking at this then:
-(unsigned int)doSomething
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
//something need to be done after returning
//process
});
return msg_id;
}
In any case, I think you need to rethink your logic.