Is it possible to check that main thread is idle / to drain a main run loop? - ios

I've just read the following post and have tried to implement the approach described there:
Writing iOS acceptance tests using Kiwi - Being Agile
All the stuff described there does work perfectly. But! there is one thing that breaks determinism when I am running my acceptance tests.
Here is the repo on Github where author of the post pushed his experiments (it can be found on the bottom of the page in the comments): https://github.com/moredip/2012-Olympics-iOS--iPad-and-iPhone--source-code/tree/kiwi-acceptance-mk1
Consider this code he uses for tapping a view:
- (void) tapViewViaSelector:(NSString *)viewSelector{
[UIAutomationBridge tapView:[self viewViaSelector:viewSelector]];
sleepFor(0.1); //ugh
}
...where sleepFor has the following definition behind itself:
#define sleepFor(interval) (CFRunLoopRunInMode(kCFRunLoopDefaultMode, interval, false))
It is a naive attempt ('naive' is not about the author, but about the fact that it is the first thing that comes into a head) to wait for a tiny period of time until all the animations are processed and soak all the possible events that were(or could be) scheduled to a main run loop (see also this comment).
The problem is that this naive code does not work in a deterministic way. There are a bunches of UI interactions which cause fx next button tap to be pressed before the current edited textfield's keyboard is disappeared and so on...
If I just increase the time from 0.1 to fx 1 all the problems disappear, but this leads to that every single interaction like "fill in textfield with a text..." or "tap button with title..." become to cost One second!
So I don't mean just increasing a wait time here, but rather a way to make such artificial waits guarantee that I do can proceed my test case with a next step.
I hope that it should be a more reliable way to wait enough until all the stuff caused by current action (all the transitions/animations or whatever main run loop stuff) are done.
To summarize it all to be a question:
Is there a way to exhaust/drain/soak all the stuff scheduled to a main thread and its run loop to be sure that main thread is idle and its run loop is "empty"?
This was my initial solution:
// DON'T like it
static inline void runLoopIfNeeded() {
// https://developer.apple.com/library/mac/#documentation/CoreFOundation/Reference/CFRunLoopRef/Reference/reference.html
while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, YES) == kCFRunLoopRunHandledSource);
// DON'T like it
if (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, YES) == kCFRunLoopRunHandledSource) runLoopIfNeeded();
}

you can try this
while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true) == kCFRunLoopRunHandledSource);
this will run until no more things in the run loop. you can try to change the time interval to 0.1 if 0 is not working.

To check on the status of a run loop associated with a thread and register callbacks for separate phases, you may use a CFRunLoopObserverRef. This allows for extremely fine grained control over when the callbacks are invoked. Also, you don't have to depend on hacky timeouts and such.
One can be added like so (notice I am adding one to the main run loop)
CFRunLoopObserverRef obs = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, kCFRunLoopAllActivities, true, 0 /* order */, handler);
CFRunLoopAddObserver([NSRunLoop mainRunLoop].getCFRunLoop, obs, kCFRunLoopCommonModes);
CFRelease(obs);
Depending on the activities you register for, your handler will get invoked appropriately. In the sample above, the observer listens for all activities. You probably only need kCFRunLoopBeforeWaiting
You handler could look like this
id handler = ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
switch (activity) {
case kCFRunLoopEntry:
// About to enter the processing loop. Happens
// once per `CFRunLoopRun` or `CFRunLoopRunInMode` call
break;
case kCFRunLoopBeforeTimers:
case kCFRunLoopBeforeSources:
// Happens before timers or sources are about to be handled
break;
case kCFRunLoopBeforeWaiting:
// All timers and sources are handled and loop is about to go
// to sleep. This is most likely what you are looking for :)
break;
case kCFRunLoopAfterWaiting:
// About to process a timer or source
break;
case kCFRunLoopExit:
// The `CFRunLoopRun` or `CFRunLoopRunInMode` call is about to
// return
break;
}
};

Here is my current solution, I will add some comments and explanations to the code a bit later, if nobody tell me I am wrong or suggests a better answer first:
// It is much better, than it was, but still unsure
static inline void runLoopIfNeeded() {
// https://developer.apple.com/library/mac/#documentation/CoreFOundation/Reference/CFRunLoopRef/Reference/reference.html
__block BOOL flag = NO;
// http://stackoverflow.com/questions/7356820/specify-to-call-someting-when-main-thread-is-idle
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
dispatch_async(dispatch_get_main_queue(), ^{
flag = YES;
});
});
while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, YES) == kCFRunLoopRunHandledSource);
if (flag == NO) runLoopIfNeeded();
}
Right now I don't have any ideas how this could be made more effective.

Related

iOS: Handling OpenGL code running on background threads during App Transition

I am working on an iOS application that, say on a button click, launches several threads, each executing a piece of Open GL code. These threads either have a different EAGLContext set on them, or if they use same EAGLContext, then they are synchronised (i.e. 2 threads don't set same EAGLContext in parallel).
Now suppose the app goes into background. As per Apple's documentation, we should stop all the OpenGL calls in applicationWillResignActive: callback so that by the time applicationDidEnterBackground: is called, no further GL calls are made.
I am using dispatch_queues to create background threads. For e.g.:
__block Byte* renderedData; // some memory already allocated
dispatch_sync(glProcessingQueue, ^{
[EAGLContext setCurrentContext:_eaglContext];
glViewPort(...)
glBindFramebuffer(...)
glClear(...)
glDrawArrays(...)
glReadPixels(...) // read in renderedData
}
use renderedData for something else
My question is - how to handle applicationWillResignActive: so that any such background GL calls can be not just stopped, but also be able to resume on applicationDidBecomeActive:? Should I wait for currently running blocks to finish before returning from applicationWillResignActive:? Or should I just suspend glProcessingQueue and return?
I have also read that similar is the case when app is interrupted in other ways, like displaying an alert, a phone call, etc.
I can have multiple such threads at any point of time, invoked by possibly multiple ViewControllers, so I am looking for some scalable solution or design pattern.
The way I see it you need to either pause a thread or kill it.
If you kill it you need to ensure all resources are released which means again calling openGL most likely. In this case it might actually be better to simply wait for the block to finish execution. This means the block must not take too long to finish which is impossible to guarantee and since you have multiple contexts and threads this may realistically present an issue.
So pausing seems better. I am not sure if there is a direct API to pause a thread but you can make it wait. Maybe a s system similar to this one can help.
The linked example seems to handle exactly what you would want; it already checks the current thread and locks that one. I guess you could pack that into some tool as a static method or a C function and wherever you are confident you can pause the thread you would simply do something like:
dispatch_sync(glProcessingQueue, ^{
[EAGLContext setCurrentContext:_eaglContext];
[ThreadManager pauseCurrentThreadIfNeeded];
glViewPort(...)
glBindFramebuffer(...)
[ThreadManager pauseCurrentThreadIfNeeded];
glClear(...)
glDrawArrays(...)
glReadPixels(...) // read in renderedData
[ThreadManager pauseCurrentThreadIfNeeded];
}
You might still have an issue with main thread if it is used. You might want to skip pause on that one otherwise your system may simply never wake up again (not sure though, try it).
So now you are look at interface of your ThreadManager to be something like:
+ (void)pause {
__threadsPaused = YES;
}
+ (void)resume {
__threadsPaused = NO;
}
+ (void)pauseCurrentThreadIfNeeded {
if(__threadsPaused) {
// TODO: insert code for locking until __threadsPaused becomes false
}
}
Let us know what you find out.

Flood main thread with consuming tasks

I would like to flood the main thread with random tasks for a certain amount of time in order to figure out how another part of my application would in this circumstances. How can I achieve this?
You could just create an while-loop that never ends. Something like:
BOOL contunue = YES;
while (contunue) {
// Code
}
That would run until you stop the program yourself.
Edit:
To add a timer to the above code, you could use NSTimer to change the value of continue to NO after a determined amount of time

Using while(true) statement a valid approach in iOS programming?

In objective C,
I am making my program to wait using while loop
doInitialize()
{
dispach_group_t loadDataGroup=dispatch_group_create();
dispatch_group_async(loadDataGroup,...get_global_queue(..),0),^{
renewauth();
}
dispatch_group_notify(loadDataGroup,...get_global_queue(..),0),^{
//Do other tasks once renew session has completed...
}
}
renewauth()
{
RenewAuthTokenInProgress=true;
startRenewThread();
**while (RenewAuthTokenInProgress);**
}
In turn startRenewThread() function also performs dispatch_async operation inside. So I have to make renewAuth() wait.
And async task in startRenewThread will update the bool variable once renewal is successful.
Is there any better approach of doing it other than dispatch_groups?
And is it good to make other threads wait with while (true) statement?
Manoj Kumar,
using a while loop to wait till the boolean variable change is not the correct approach to solve the problem. Here are few of the issues with this method
Your CPU is un-necessarily burdened with checking the variable regularly.
This will clearly show that developer isn't much equipted with basic skills of coding and features available with language.
If for any reason your variable will never change then your CPU will never stop checking the value of bool in while loop and blocks the execution of further code on the same thread.
Here are few of the correct approach :
Blocks or closures : Make use of blocks to execute the code asynchronously when the RenewAuthToken is done.
Delegates : if blocks are harder to understand, Make use of delegates and trigger the delegate when you are done with RenewAuthToken.
Notifications : Add observer for notifications in classes which needs to respond when RenewAuthToken is done and throw notification from the asynctask and let the class to catch it execute the code.
Locks : If it is necessary to block the execution of the thread till the response comes use locks to control the thread execution rather than using while loop
EDIT
As pointed out by fogmeister in comments
If you block the main thread for too long with a while(true) loop then
the app will actually be terminated by the iOS Watchdog as it will
assume it has crashed
Please have a look at the link : understand iOS watchdog termination reasons provided by fogmeister
Hope it helps.
I believe what you need it's a semaphore like:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
__block BOOL done = FALSE;
while (true) {
[self someCompletionMethod completion:^(BOOL success) {
if(success) { // Stop condition
done = TRUE;
}
// do something
dispatch_semaphore_signal(sem); // This will let a new iteration
}];
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
if(done) {
dispatch_async(dispatch_get_main_queue(), ^{
// Dispatch to main
NSLog(#"Done!");
break;
});
}
}
});
Semaphores are an old-school threading concept introduced to the world by the ever-so-humble Edsger W. Dijkstra. Semaphores are a complex topic because they build upon the intricacies of operating system functions.
You can see a tutorial here about semaphore and check it out more links: https://www.raywenderlich.com/63338/grand-central-dispatch-in-depth-part-2
I hope this can help you.
What you do is absolutely lethal. It blocks the running thread (presumably the main thread) so the UI is frozen. It runs one core at 100% load for no reason whatsoever which empties the battery rapidly and heats up the phone. This will get you some very, very unhappy customers or very, very happy ex-customers.
Anything like this has to run in the background: startRenewThread should trigger some action that sets RenewAuthTokenInProgress = NO and sets whether there is a new token or not, and then triggers further action.
This is an absolutely essential programming pattern on iOS (and Android as far as I know).

Know when all SKActions are complete or there aren't any running

I have a number of SKActions running on various nodes. How can I know when they are all completed? I want to ignore touches while animations are running. If I could somehow run actions in parallel on a number of nodes, I could wait for a final action to run, but I don't see any way to coordinate actions across nodes.
I can fake this by running through all the scene's children and checking for hasActions on each child. Seems a little lame, but it does work.
The simplest way to do this is using a dispatch group. In Swift 3 this looks like
func moveAllNodes(withCompletionHandler onComplete:(()->())) {
let group = DispatchGroup()
for node in nodes {
let moveAction = SKAction.move(to:target, duration: 0.3)
group.enter()
node.run(moveAction, completion: {
...
group.leave()
}
}
group.notify(queue: .main) {
onComplete()
}
}
Before running each action we call group.enter(), adding that action to the group. Then inside each action completion handler we call group.leave(), taking that action out of the group.
The group.notify() block runs after all other blocks have left the dispatch group.
To my knowledge there is no way to do this via the default framework capabilities.
However, I think you could achieve something like this by creating a class with methods that act as a wrapper for calling SKAction runAction: on a node.
In that wrapper method, you could push the node into an array, and then append a performSelector action to each action/group/sequence. So whatever method you specify gets called after completion of the action/group/sequence. When that method is called, you can just remove that node from the array.
With this implementation you would always have an array of all nodes that currently have an action running on them. If the array is empty, none are running.
Each action you run has a duration. If you keep track of the longest running action's duration you know when it'll be finished. Use that to wait until the longest running action is finished.
Alternatively, keep a global counter of running actions. Each time you run an action that pauses input increase the counter. Each action you run needs a final execute block that then decreases the counter. If the counter is zero, none of the input-ignoring actions are running.
It looks like in the two years since this question was first posted, Apple has not extended the framework to deal with this case. I was hesitant to do a bunch of graph traversals to check for running actions, so I found a solution using an instance variable in my SKScene subclass (GameScene) combined with the atomic integer protection functions found in /usr/include/libkern/OSAtomic.h.
In my GameScene class, I have an int32_t variable called runningActionCount, initialized to zero in initWithSize().
I have two GameScene methods:
-(void) IncrementUILockCount
{
OSAtomicIncrement32Barrier(&runningActionCount);
}
-(void) DecrementUILockCount
{
OSAtomicDecrement32Barrier(&runningActionCount);
}
Then I declare a block type to pass to SKNode::runAction completion block:
void (^SignalActionEnd)(void);
In my method to launch the actions on the various SKSpriteNodes, set that completion block to point to the safe decrement method:
SignalActionEnd = ^
{
[self DecrementUILockCount];
};
Then before I launch an action, run the safe increment block. When the action completes, DecrementUILockCount will be called to safely decrement the counter.
[self IncrementUILockCount];
[spriteToPerformActionOn runAction:theAction completion:SignalActionEnd];
In my update method, I simply check to see if that counter is zero before re-enabling the UI.
if (0 == runningActionCount)
{
// Do the UI enabled stuff
}
The only other thing to note here is that if you happen to delete any of the nodes that have running actions before they complete, the completion block is also deleted (without being run) and your counter will never be decremented and your UI will never re-enable. The answer is to check for running actions on the node you are about to delete, and manually run the protected decrement method if there are any actions running:
if ([spriteToDelete hasActions])
{
// Run the post-action completion block manually.
[self DecrementUILockCount];
}
This is working fine for me - hope it helps!
I was dealing with this issue while fiddling around with a sliding-tile type game. I wanted to both prevent keyboard input and wait for as short a time as possible to perform another action, while the tiles were actually moving.
All the tiles that I was concerned about were instances of the same SKNode subclass, so I decided to give that class the resposibility for keeping track of animations in progress, and for responding to queries about whether animations were running.
The idea I had was to use a dispatch group to "count" activity: it has a built-in mechanism to be waited on, and it can be added to at any time, so that the waiting will continue as long as tasks are added to the group.*
This is a sketch of the solution. We have a node class, which creates and owns the dispatch group. A private class method allows instances to access the group so they can enter and leave it when they are animating. The class has two public methods that allow checking the group's status without exposing the actual mechanism: +waitOnAllNodeMovement and +anyNodeMovementInProgress. The former blocks until the group is empty; the latter simply returns a BOOL immediately indicating whether the group is busy or not.
#interface WSSNode : SKSpriteNode
/** The WSSNode class tracks whether any instances are running animations,
* in order to avoid overlapping other actions.
* +waitOnAllNodeMovement blocks when called until all nodes have
* completed their animations.
*/
+ (void)waitOnAllNodeMovement;
/** The WSSNode class tracks whether any instances are running animations,
* in order to avoid overlapping other actions.
* +anyNodeMovementInProgress returns a BOOL immediately, indicating
* whether any animations are currently running.
*/
+ (BOOL)anyNodeMovementInProgress;
/* Sample method: make the node do something that requires waiting on. */
- (void)moveToPosition:(CGPoint)destination;
#end
#interface WSSNode ()
+ (dispatch_group_t)movementDispatchGroup;
#end
#implementation WSSNode
+ (void)waitOnAllNodeMovement
{
dispatch_group_wait([self movementDispatchGroup],
DISPATCH_TIME_FOREVER);
}
+ (BOOL)anyNodeMovementInProgress
{
// Return immediately regardless of state of group, but indicate
// whether group is empty or timeout occurred.
return (0 != dispatch_group_wait([self movementDispatchGroup],
DISPATCH_TIME_NOW));
}
+ (dispatch_group_t)movementDispatchGroup
{
static dispatch_group_t group;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
group = dispatch_group_create();
});
return group;
}
- (void)moveToPosition:(CGPoint)destination
{
// No need to actually enqueue anything; simply manually
// tell the group that it's working.
dispatch_group_enter([WSSNode movementDispatchGroup]);
[self runAction:/* whatever */
completion:^{ dispatch_group_leave([WSSNode movementDispatchGroup])}];
}
#end
A controller class that wants to prevent keyboard input during moves then can do something simple like this:
- (void)keyDown:(NSEvent *)theEvent
{
// Don't accept input while movement is taking place.
if( [WSSNode anyNodeMovementInProgress] ){
return;
}
// ...
}
and you can do the same thing in a scene's update: as needed. Any other actions that must happen ASAP can wait on the animation:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
^{
[WSSNode waitOnAllNodeMovement];
dispatch_async(dispatch_get_main_queue(), ^{
// Action that needs to wait for animation to finish
});
});
This is the one tricky/messy part of this solution: because the wait... method is blocking, it obviously has to happen asynchronously to the main thread; then we come back to the main thread to do more work. But the same would be true with any other waiting procedure as well, so this seems reasonable.
*The other two possibilities that presented themselves were a queue with a barrier Block and a counting semaphore.
The barrier Block wouldn't work because I didn't know when I could actually enqueue it. At the point where I decided to enqueue the "after" task, no "before" tasks could be added.
The semaphore wouldn't work because it doesn't control ordering, just simultaneity. If the nodes incremented the semaphore when they were created, decremented when animating, and incremented again when done, the other task would only wait if all created nodes were animating, and wouldn't wait any longer than the first completion. If the nodes didn't increment the semaphore initially, then only one of them could function at a time.
The dispatch group is being used much like a semaphore, but with privileged access: the nodes themselves don't have to wait.

iOS. Save state when user exits an application?

For example:
- (void)someFunc {
[self someFunc1];
[self someFunc2];
[self someFunc3];
}
I call someFunc. As I understand if I interrupt the application then the application doesn't guarantee that all the inner code in someFunc will be performed.
I must call someFunc1, someFunc2 and someFunc3 only once.
The problems I don't know how to solve:
someFunc1, someFunc2 and someFunc3 should be called atomically.
storing info for next launch. For example if we successfully have performed someFunc1 only then at next launch the application should call someFunc2 and someFunc3 only.
I know about method applicationWillTerminate:, but I don't know how to solve the current issue with it.
EDITED
Multitasking is not a solution because Even if the device is running iOS 4 or later, the device may not support multitasking., so it doesn't solve the general problem and makes the final solution more difficult only.
EDITED
For those who spam with off topic answers: read the title first - Save state when user exits an application. Where have you seen here putting the application into background?
This does't make sense. If these functions are running on the main thread, there is no way that the application can terminate normally while your functions are running. This is because the events sent like applicationWillTerminate: are sent on the same thread.
If your function is running on a different thread to the main thread, you will need to save some state information after each function completes, but you still have a race condition.
It might be better to check your application's state before running each function. For example, if you have a three step login/registration process with a server, you should query the server to see if the stage has been completed already before running it.
It's difficult to be more specific without knowing what you are doing in these functions.
You should use background tasks !
Take a look at the documentation here :
Executing a Finite-Length Task in the Background
Put the call of someFunc in the middle of the background task.
If your app goes to the background state, you'll have extra time to finish the execution of the method.
Make your functions to return bool, and when you call them, store the bool value to nsdefaults.
When the app restarts,check the bools from sndefaults, and if they are NO, run the functions and update them.
Nobody wants to help. So my temporary solution:
to save a last state I use a writing to a file because it enables to set its operation as atomic/nonatomic
I have replaced this code with something like this:
typedef enum {
state1,
state2,
state3
} MyState;
#property (assign) MyState state;
-(void)someFunc {
switch (state) {
case state1:
{
[self someFunc1];
state = state2;
[self someFunc];
break;
}
case state2:
{
[self someFunc2];
state = state3;
[self someFunc];
break;
}
default:
break;
}
}

Resources