How to loop despatch_after - ios

I want to loop dispatch_after for looping showing images like this:
while isRunning {
let delay = Int64(Double(NSEC_PER_SEC) * settings.delay)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delay), dispatch_get_main_queue(), {
dispatch_async(dispatch_get_main_queue(), {
self.showNextImage()
})
})
}
It supposed to call showNextImage every delay seconds. But it stucks in infinite loop without showing images. I dont know how to solve this problem. Any help is appreciated.

Loop is dispatching infinite dispatch_after because isRunning is yes and loop is not waiting , better to put some count (i<10) or use NSTimer to certain condition then invalidate.
if (self.stimerShowNextImage.isValid) {
[self.stimerShowNextImage invalidate];
self.stimerShowNextImage = nil;
}
self.stimerShowNextImage = [NSTimer scheduledTimerWithTimeInterval: 5
target: self
selector: #selector(showNextImage)
userInfo: nil
repeats: YES];
Above is the timerCode with 5 second delay , in ViewWillDisapper you need to invalidate it , Also before scheduling timer you need to check its not already running.

Look in your code dispatch_after already running in main thread. And again inside main thread using. i mean not need.
when it is need means if u r using other than main thread outside and after u r using uielements, that time use main thread inside.

Related

asyncAfter with no time seems delay - Swift

Eventually I have used asyncAfter feature in swift with no time, and it does some delay and seems different with normal code.
Code with async:
DispatchQueue.main.asyncAfter(deadline: .now() + 0.0 , execute: {
self.updateUI()
})
Normal code:
self.updateUI()
Similar problem with perform selector also.
self.performSelector("onFlip", withObject: nil, afterDelay: 0)
Is that delay is caused because of creating new thread?
This is expected.
DispatchQueue.main.asyncAfter(deadline: .now() + 0.0 , execute: {
self.updateUI()
})
Is essentially the same as
DispatchQueue.main.async {
self.updateUI()
}
which also won't execute immediately due to the fact that you dispatch the code to the main thread asynchronously. Due to the async dispatch, the code inside the closure won't be executed immediately, only on the next runloop of main, which might result in a measurable delay .
asyncAfter doesn't create a new thread, since you are dispatching on the main queue, which will use the main thread, but neither will it execute the dispatched code immediately.
You have submitted a block of code to run on the main queue, so some time will elapse before the runloop can execute that code; particularly if the asyncAfter is being called on the main thread.

Subsequent WKInterfaceTime / NSTimer events with array of NSTimeInterval values

I am trying to run subsequent Timer events with WKInterfaceTimer & NSTimer, the problem is that I cannot figure out a way to make more than two subsequent calls with one NSTimer object. Basically, I would like run timer to complete then fire up the next.
Here's some sample code that hopefully explains my idea a little better....
1) I am firing off the first timer in awakeWithContext:
func initalTimer() {
let timer1String = NSMutableAttributedString(string: "Lap1")
runStatusLabel.setAttributedText(timerString)
myTimer = NSTimer.scheduledTimerWithTimeInterval(duration, target: self, selector: Selector("timerDone"), userInfo: nil, repeats: false)
runTimer.setDate(NSDate(timeIntervalSinceNow: duration))
runTimer.start()
}
NOTE: Everything works great at this point, then the tiemrDone function is called where I then fire off another timed event.
2)
func timerDone() {
//print("Done")
elapsedTime = 0.0
myTimer!.invalidate()
startTime = NSDate()
timeRunning = false
// Call second timed event
timer2() // just another NSTimer / WKInterfaceTimer function
}
"Stacking" the functions with a completionHandler does not seem to help OR most likely I am doing something wrong...
func execute_Timers(timeInterval: NSTimeInterval, completionHandler: (success: Bool, error: String?) -> Void ) -> Int {
// Code below never gets executed
}
I haven't tested this, and it is just a guess: When your timerDone() method is called, you invalidate the timer. Therefore it doesn't "complete," so your completion routine isn't called. When your timer completes, it gets invalidated anyway, so the call should not be needed. Try removing:
myTimer!.invalidate()
and see what happens.
Thanks for the reply, and you are quite correct - I do not need to call myTimer!.invalidate(). The solution that worked for me was to have different timerDone methods and conditionaly call the next time method.
-Paul

In Swift, what is the easiest way to call a method in 5 seconds (non-blocking)?

I have this, but seems overly complicated:
var connectionTimer = MZTimerLabel(timerType: MZTimerLabelTypeTimer)
connectionTimer.delegate = self
connectionTimer.tag = 0
connectionTimer.setCountDownTime(5)
connectionTimer.start()
func timerLabel(timerLabel: MZTimerLabel!, finshedCountDownTimerWithTime countTime: NSTimeInterval) {
self.callFinished()
}
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC), dispatch_get_main_queue()) {
self.callFinished()
}
This is part of the awesome and versatile library Grand Central Dispatch, which will allow you to perform not just delays but all sorts of concurrent operations you will almost certainly have threading bugs in! Luckily, since in your case you are calling back to the main queue, none of your code will execute concurrently, so there's nothing to worry about in this case.
Try this
let delayTimer = NSTimer.scheduledTimerWithTimeInterval(5.0, target: self, selector: Selector("delayed"), userInfo: nil, repeats: false)
func delay() { println ("hi") }
It will call delay five seconds later.

iOS Unit Testing: Wait for Time Interval with Expectations

I'm trying to update my asynchronous unit tests to use the new XCTestExpectation interface instead of manually spinning the run loop.
My unit tests previously utilized the functions waitForBlock, finishBlock, and waitForTimeInterval: which is simply a convenience method that called finishBlock after the specified time. I'm trying to update this setup to use expectations.
The tests that were utilizing waitForBlock + finishBlock semantics are all working just as expected after being replaced with waitForExpectationsWithTime:handler: and fulfill, but my solution to replace waitForTimeInterval: doesn't seem to be working.
- (void)waitForTimeInterval:(NSTimeInterval)delay
{
XCTestExpectation *expectation = [self expectationWithDescription:#"wait"];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[expectation fulfill];
});
[self waitForExpectationsWithTimeout:delay + 1 handler:nil];
}
Edit:
Seems like that code actually does work... so this was probably just Xcode 6 screwing with me this afternoon.
I feel like it should be fairly straight-forward: Create an expectation, set up an asynchronous block that fulfills is, and wait. However, the dispatch_after block is never invoked.
My hunch is that waitForExpectationsWithTimeout:handler: blocks its current thread, which is the main queue, so the run loop never gets around to its asynchronous blocks. That seems reasonable, but I'm having trouble coming up with a different way to implement this functionality.
I'm looking for either 1) additional information about XCTestExpectation that might reveal a workaround, or 2) a different idea for implementing this functionality.
dispatch_async(dispatch_get_main_queue(), ...) doesn't seem to work in Xcode 7 UI Tests, the completion handler is never called. performSelector is no longer available in Swift, but there are two other workarounds:
Using a timer
var waitExpectation: XCTestExpectation?
func wait(duration: NSTimeInterval) {
waitExpectation = expectationWithDescription("wait")
NSTimer.scheduledTimerWithTimeInterval(duration, target: self,
selector: Selector("onTimer"), userInfo: nil, repeats: false)
waitForExpectationsWithTimeout(duration + 3, handler: nil)
}
func onTimer() {
waitExpectation?.fulfill()
}
Run the block on global queue (it works, but probably unsafe as it's not documented anywhere that XCTestExpectation is thread-safe).
func wait(duration: NSTimeInterval) {
let expectation = expectationWithDescription("wait")
let dispatchTime = dispatch_time(DISPATCH_TIME_NOW,
Int64(duration * Double(NSEC_PER_SEC)))
dispatch_after(dispatchTime,
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
expectation.fulfill()
}
waitForExpectationsWithTimeout(duration + 3, handler: nil)
}
I've used XCTestExpectation in a number of projects for all sorts of async web and GCD stuff... AFAIK, something like the following is what seems to be the most common usage:
- (void)testExample {
// create the expectation with a nice descriptive message
XCTestExpectation *expectation = [self expectationWithDescription:#"The request should successfully complete within the specific timeframe."];
// do something asyncronously
[someObject doAsyncWithCompletionHandler:^(NSInteger yourReturnValue) {
// now that the async task it done, test whatever states/values you expect to be after this is
// completed
NSInteger expectedValue = 42;
XCTAssert(yourReturnValue == expectedValue, #"The returned value doesn't match the expected value.");
// fulfill the expectation so the tests can complete
[expectation fulfill];
}];
// wait for the expectations to be called and timeout after some
// predefined max time limit, failing the test automatically
NSTimeInterval somePredefinedTimeout = 3;
[self waitForExpectationsWithTimeout:somePredefinedTimeout handler:nil];
}
Apparently using performSelector:withObject:afterDelay: works as expected, though I'm still not sure why. If anyone has an idea as to why GCD's dispatch_after doesn't work, please provide an additional answer and I will accept it. For now, this setup seems to work as expected:
- (void)waitForTimeInterval:(NSTimeInterval)delay
{
XCTestExpectation *expectation = [self expectationWithDescription:#"wait"];
[self performSelector:#selector(fulfillExpectation:) withObject:expectation afterDelay:delay];
[self waitForExpectationsWithTimeout:delay + 1 handler:nil];
}
- (void)fulfillExpectation:(XCTestExpectation *)expectation
{
[expectation fulfill];
}
In one of my Unit test cases I needed to test the running of a method in my main app code, which should trigger a timer in about 1 second to call another method in the app. I used XCTestExpectation wait and DispatchQueue.asyncAfter as a mechanism to stop and wait before I check the result. The following code is a snippet in Swift 3 / 4:
<call the main app method which will trigger a timer event>
// wait
let expectation = XCTestExpectation(description: "test")
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2) {
expectation.fulfill()
}
wait(for: [expectation], timeout: 2.5)
<check the result of the timer event>

Timing issue with dispatch_source_t handler function - am I following the right pattern for dispatch timer?

I read the documentation and came to know that timer (dispatch_source_t) skips to fire if the handler is still in progress for previous iterations.
But this whole business of handler taking it longer makes this inaccurate. And I am observing that I am unable to stop the timer at intended times.
My code looks like this:
double secondsToFire = 1.0f;
dispatch_queue_t queue = dispatch_get_main_queue();
m_myTimer = CreateDispatchTimer(secondsToFire, queue,
^{
//Do some time consuming operation, taking any number of seconds
int retVal = DoSomeOperation();
if (retVal == 1)
{
cancelTimer(m_myTimer);
SomeOtherOperation();
}
});
dispatch_source_t CreateDispatchTimer(double interval, dispatch_queue_t queue, dispatch_block_t block)
{
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
if (timer)
{
// dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, interval * NSEC_PER_SEC), interval * NSEC_PER_SEC, (1ull * NSEC_PER_SEC) / 10);
dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, 0), interval * NSEC_PER_SEC, 0);
dispatch_source_set_event_handler(timer, block);
dispatch_resume(timer);
}
return timer;
}
void cancelTimer(dispatch_source_t _timer)
{
if (_timer)
{
dispatch_source_cancel(_timer);
_timer = nil;
}
}
Note:
Inside DoSomeOperation(), I have code enclosed with #synchronized(array), in which I access an array who is being written by another private queue. But entire DoSomeOperation() is executed on main queue.
My question is, is this is the right and accurate timing model? I am posting here because I am facing lot of inaccuracies - timer doesn't fire every second, and it doesn't stop as intended too. I am able to observe that SomeOtherOperation() gets called when retVal == 1, but timer isn't done yet.
Another Note:
m_myTimer above is an iVar, and my project is ARC, if that could make any difference.
No, a dispatch timer doesn't get "skipped" if it fires while your handler is running, the handler will get re-invoked for the pending event right away once the previous invocation returns.
If multiple firings occur while the handler is running or enqueued (or while the source is suspended), they will get all get coalesced into a single handler invocation (as is the case for all edge-triggered source types).
You can check how many firings a given handler invocation is for with dispatch_source_get_data()
My concern was about accuracy in starting, firing and stopping, and not in correct reporting of things.
I finally ended up assigning one of my tasks off a private queue instead of main one. The advantage could be clearly visible in timer accuracy and prompt timer cancellation.
Conclusion:
More the same (esp. main) queue getting flogged by timer tasks, more they become inaccurate.

Resources