Why is runloop called when testing - ios

I usually see RunLoop.current.run(until: Date()) called in integration tests.
For example in this article and in this open source project.
The explanation given in the article is
The RunLoop.current.run(until: Date()) statement makes sure the run loop associated with the current thread has ample time to let the drawing operations to complete
If that is true why wouldn't we give it more time, how do we know that Date() is enough?
I read a few articles about the run loop and it seems to me like the reason that line of code is added is to start the app. It seems like the appDelegate usually automatically triggers or starts the run loop, but since we are testing we need to trigger the run loop ourselves.
I might be missing some fundamental understand of threads or run loops but I hope that someone can give some insight.

If that is true why wouldn't we give it more time, how do we know that Date() is enough?
We know from experimentation, I suppose. A more “correct” way to do it would be:
Install a run loop observer that somehow detects when the views have been laid out and drawn.
Run the run loop indefinitely (until Date.distantFuture).
In the observer installed in step 1, call CFRunLoopStop(CFRunLoopGetMain()) when it detects that the views have been laid out and drawn.
However, that's a lot of extra work to do instead of just RunLoop.current.run(until: Date()), when the simpler method works and is unlikely to break.
I read a few articles about the run loop and it seems to me like the reason that line of code is added is to start the app. It seems like the appDelegate usually automatically triggers or starts the run loop, but since we are testing we need to trigger the run loop ourselves.
No, the app delegate does not start the run loop. The function UIApplicationMain sets up the app and starts the run loop. If you create a new Objective-C project, you will find that the main function in main.m calls UIApplicationMain. In a typical Swift project, the #UIApplicationMain attribute attached to the app delegate tells the Swift compiler to generate equivalent code (a main function that calls UIApplicationMain) in AppDelegate.o.
I might be missing some fundamental understand of threads or run loops but I hope that someone can give some insight.
An app spends most of its life in the run loop, which (simplified) has these phases:
Wait for an event. There are lots of event sources, including app startup, touches, timers, accelerometer, GPS, going to the background, returning to the foreground, and more.
Handle the event, often by calling code written by you.
If any views have the needsLayout property set, lay out the appropriate sections of the view hierarchy (which includes sending layoutSubviews messages).
If any views have the needsDisplay property set, draw those views (by sending drawRect: messages).
Go back to step 1.

Related

Lua - How would I have a wait command for events without waiting for the wait to finish

I have tried different wait/sleep commands which completely stops the code. In my code I have changed events, so if something was changed there is a wait/sleep command, but it will wait for that event to completely finish even if another event is called. How would I have it so there would still be a delay, but have it so the events called during the wait period will run, and not wait for the previous event.
There are two approaches:
1) "Fake" parallelism based on event loop:
Project "luvit" realizes this approach, trying to do for Lua those things that node.js doing for JavaScript. In my humble opinion, for such approach just use node.js, luvit is weird and is not very reliable.
2) Multi threading:
It is better for perfomance of application, but it is more complex way, it will take time to figure out how to work with it.
For this approach use Lua Lanes.
Also, if you need it inside OpenResty, it has tools for this.
If you need it in small script, though I love Lua with all my heart, you should consider switching to node.js

intercept all objective c method calls

I wish to insert hooks whenever a method is called in my iOS app. So lets say there is a selector X, I wish to log "Method X starting" before the method executes, and then log "Method X ended" after the execution. I am aware of an approach where I can swizzle the implementation of sel X with the one which has the hook before and after the call to "itself", so that I can be notified when the method has executed. But, this will only work if i know the method in advance. I wish to insert hooks for all the methods that execute, even if I do not have access to the source code of the class executing it (for example a third party closed library executing an internal method). The intent behind this is logging the time taken for execution of each and every method in my app. I am aware that I cannot override objc message send method call to intercept methods. Does NSObject have some functions that are called before and after a method gets executed?
It sounds like what you actually want is to run your app in Instruments' "Time Profiler" tool. This will log all the method invocations for you and show you which ones are taking the greatest amount of time in your app.
To answer your original question, you don't actually have to know the methods ahead of time; you can just use class_copyMethodList() to get a list of methods and then iterate over them. I would discourage actually going this route, though, as Instruments is a better tool for this sort of thing.
Believe me you don't want this. As you think on a higher level that calling a function and logging the start and end to it is good, it won't do you any good for the following reasons:
1- Function will call many many lower level fuctions: addSubview itself will call many functions alone, and the function it calls will call many fuctions inside as well. You think you are about to call 1 function, but this log will be triggered +20 times in this case.
2- logging all functions is actually extra code in your case. Extra code means extra effort to the app. What you will do is basically impact the performance and battery usage dramatically.
3- Apple makes sure its core functions are seriously optimized and spends a lot of time on them to ensure they are at their best (in some xCode releases they are updated as well)
My advice is to log your functions, if you're trying to achieve a specific goal. but generally logging objective c is not recommended.
PS: In case you are trying to check the time for every function, there are tools that will show you which functions are taking what times.

Where to put code that gets checked frequently?

I have some code that needs to get called frequently, such as check what day it is, if it's the next day then move the day strings in the tableView.
Now I thought that the viewDidLoad would get called all the time and so it would be 'fine' to put it in there. However, I've left the simulator overnight, and I've pressed the home button and clicked again, changed VCs etc. and viewDidLoad hasn't been hit.
What are my options for doing sporadic checks such as, is it a new day? As x happened etc.
In this specific case, you can subscribe to NSCalendarDayChangedNotification to be notified when the date changes and respond accordingly in your view controller. In general, didBecomeActive or viewDidAppear would likely work.
What are my options for doing sporadic checks such as, is it a new day
It depends what the meaning of "is" is! In particular, "is" when? You say "sporadic", but that's just fluff. When do you need to know this? To what stimulus do you want to respond? When the user opens your app? Then put it in applicationDidBecomeActive. Every day at noon? Then run an NSTimer. Really, the problem here is that you don't seem to know, yourself, just when you need to perform these checks.
Whilst in your app, its quite easy to continually check for something. You simply create a background thread. However, what you describe is a thread that persists from outside the app's lifecycle.
Have a read on this documentation provided by Apple itself. You have to have good excuse to put a background thread. The scope of such thread is limited to only certain scenarios such as downloading background stuff, playing sounds etc.
For your scenario, I'd look at applicationDidBecomeActive(_:) found in your Application Delegate. There you can mimic such continual check. Beware however, don't put heavy word load on start up or your app might be killed automatically if it fails to become active in reasonable amount of time.

What's the difference between main event loop and app's run loop?

I tried to find the difference between those two loops in the internet but I didn't find any. I have read some articles they explained in such a way that both are same. I was been asked what's the difference between them and I have said what's there in the arictles. Interviewer said both are not same. So please help me guys what's the difference. Any kind of help is appreciated.
A run loop (NSRunLoop or CFRunLoop) is an event loop. The app's main thread runs a run loop; this is the app's main event loop. Most apps don't have another run loop (at least not one visible to you as a user of the iOS SDK).
If the interviewer thinks there's a difference between an event loop and a run loop on iOS, you'll have to ask them what they mean, because according to Apple's documentation they are the same thing.
https://developer.apple.com/library/ios/documentation/General/Conceptual/Devpedia-CocoaApp/MainEventLoop.html
For each app it should only have one main event loop that is inside the main thread.
I'm not sure about what's the app's run loop in the interviewer's opinion. But run loop is actually a concept binding with thread. Each NSThread object, including the application’s main thread, has an NSRunLoop object automatically created for it as needed. said in https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSRunLoop_Class/index.html#//apple_ref/doc/uid/TP40003725
I guess the main run loop is a kind of event loop.
there are two figures in
https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/TheAppLifeCycle/TheAppLifeCycle.html
(figure 2-1 and figure 2-2)
Figure 2-1 show that the event loop is some loop runs as a part of the controller and figure 2-2 show that the main run loop is the loop used by iOS to manage events.
sorry for my bad English.

iOS - Is is possible to pause execution, allow the main loop to run, then resume execution?

Is is possible in an iOS app to do the following:
Pause execution of a method running on the main thread.
Allow the main thread to continue, completing one loop of the main run loop (or continuing for a specified time period)
Resume execution of the previous paused method
?
I've searched and can't find anything that allows me to do this, but I have a feeling I've seen it done in the past by a programmer I previously worked with.
The motivation for this is the following:
I'm writing a test of a message routing class
The test (a) sends a message and then (b) analyses the outcome to determine if the test passed
The send message is sent using performSelectorOnMainThread:withObject:waitUntilDone:NO
There are 2 ways I can think to resolve this:
Split my test up and use performSelector:withObject:afterDelay:
Specify YES for waitUntilDone when sending the message
Both of these solutions are ok, but 1. complicates the test quite a lot, and 2. changes the messaging system I'm writing tests for, so will have to be carefully considered.
Considering what performSelectorOnMainThread:withObject:waitUntilDone:YES does, it seems like the functionality I'm asking for should be possible (as it's similar in many ways), but is it possible?
This might be what you're looking for:
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate date]];
This will execute one iteration of the main run loop and then continue on from there. This is kind of abusing the way the run loop is supposed to work though, so you might want to consider a different design - it's almost never a good idea to pause the main thread. Maybe do what you need to do in a separate thread and have that thread call back to a delegate method when it's done, or use a notification.
Use multithreading for this purpose. SENDER on the mainThread, WATCHER on a secondThread, what allows you to start WATCHING before SENDING.

Resources