Break out of while loop after 5 seconds in Swift - swift

I want to timeout and break out of this loop in 5 seconds. Only thing I could find online is having a count variable increment every second and then breaking if the count is 5, but was wondering if there's an easier, less codier way. Please help!
locationManager.startUpdatingLocation()
while (locationManager.location == nil) {
//searching...
}
locationManager.stopUpdatingLocation()

The problem with having a while loop is that it will block the user's use of the application if it's on the main thread. Instead of doing that, you should start updating the location and then schedule a background thread using GCD (assuming you're on OSX; GCD isn't available on Linux yet) to run in a five seconds to disable the location manager. You could also schedule it to run in one second, check to see if it's present and then either attempt again or just let it run for five seconds.

you can create a delay function like this:
func delay(delay:Double, closure:()->()) {
dispatch_after(
dispatch_time( DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC))), dispatch_get_main_queue(), closure)
}
and after use it like this:
delay(5){
locationManager.location = //something different from nil or you can try with break sentence ; not sure if with break will work though .
}

Related

How to stop an UIView animation in swift

I'm working with Swift language. I wrote an animation for a timer that lasts for 30 seconds and is full. Now I want to stop this animation, but I do not know how! I want to be able to start again from the beginning. Animation.
Thanks if you have a solution or a method that helps me🙏
You can try
self.myView.layer.removeAllAnimations()
Two possible ways:
Somewhere store variable for total time. And in every timer repeat increase this value. When total time reaches 30 seconds, remove animation
When you start animation, set action which gets executed after specific time
First possible way:
var time: Double = 0
#objc func timerChangedValue() {
time += 1
if time == 30 {
view.layer.removeAllAnimations()
view.layoutIfNeeded()
}
}
Second possible way:
DispatchQueue.main.asyncAfter(deadline: .now() + 30) {
self.view.layer.removeAllAnimations()
self.view.layoutIfNeeded()
}

action does not wait till function call ends

I have 2 actions that i put in a sequence. In the first action I am calling a method to calculate the new waiting time for the next action. The next action is just a wait for this duration, but the second action always executes straight away, so the time must be 0. I debugged it and in the method spawnFlowers i get the time returned as 3.5 seconds.
these are my 2 actions
let spawnFlowerAction = SKAction.run {
self.WaitTime = self.calculateWaitingTime()
}
let waitForNewFlower = SKAction.wait(forDuration: self.WaitTime)
I execute it this way:
let spawnSeq = SKAction.sequence([spawnFlowerAction, waitForNewFlower])
let spawnRepeat = SKAction.repeat(spawnSeq, count: 4)
self.run(spawnRepeat)
Result: 4 times spawned without waiting, printing 4 different calculated times in the console from the calculateWaitingTime function (in which the spawning happens)
What is a good way to fix this?
The problem is trying to dynamically change the values used within SKActions after the action has been created. For example when your WaitTime variable changes while running the spawnFlowerAction, the waitForNewFlower Action's wait time won't change dynamically because it doesn't reference WaitTime. Instead its wait value is whatever your variable WaitTime was when you declared let waitForNewFlower = SKAction.wait(forDuration: self.WaitTime) (Which I'm guessing was initially 0). Same concept goes with your other two spawn actions.
I usually use the dispatch Queue for things like these, but to use SKActions here's a function. Just call it once and input the number of times you want it to repeat.
func spawnRepeat(count: Int) {
//Put whatever code to spawn flower here
print("SPAWN FLOWER")
if count > 1 {
//Recalculate WaitTime
WaitTime = calculateWaitingTime()
let waitAction = SKAction.wait(forDuration: WaitTime)
run(waitAction, completion: { self.spawnRepeat(count: count - 1) })
}
}

Swift 2 executing function after 3 seconds

I am trying to simply execute a function after 3 seconds in swift 2. I have tried numerous things and none work. It is a sprite kit game in swift 2, Pleas tell me how to do this..
calling the function now looks like this
self.adjustScore()
EDIT Solved like this, thanks googe page 4
let triggerTime = (Int64(NSEC_PER_SEC) * 1)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, triggerTime), dispatch_get_main_queue(), { () -> Void in
self.adjustScore()
})
})
Normally I would downvote the above answers, but the OP did not specify it is SpriteKit in the question title. In SpriteKit, you do not want to use NSTimers or dispatch timers, because if you pause the scene, you do not pause these timers. Instead, use a combination of SKAction.waitForDuration and SKAction.runBlock to achieve the desired effect
self.runAction(SKAction.sequence([SKAction.waitForDuration(3),SKAction.runBlock({[[unowned self] in self.adjustScore()})])
Try this:
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(3.0 * Double(NSEC_PER_SEC)))
dispatch_after(time, dispatch_get_main_queue()) {
self.adjustScore()
}

How can I create delay inside while loop in Swift 2?

I would need help with this while loop - what I'm trying to do is slow down the whole process of removing and adding new circles while radius is changing every time this happens. I'm becoming really desperate, I've tried using both dispatch_after and sleep inside the loop (which I found online) but neither of them is suitable, they basically stop the whole app. If I put them in the while loop, nothing happens. Thanks in advance!
while radius < 100 {
self.removeAllChildren()
addCircle()
radius++
print(radius)
}
Basically you just need to do few simple things:
Wait for a certain duration and add a node to the scene
Repeat this step forever (or certain number of times)
Here is the example of how you can do it. The important part is action sequence. You create the step above, and repeat it forever. Each time you check radius value and based on that you stop the action (remove it by the key). And that's it. You can change spawning speed by changing action's duration parameter.
Using NSTimer might seem like an easier solution, but NSTimer doesn't respect node's (or scene's or view's) paused state. So, imagine this situation:
You start spawning of nodes
User receive phone call and app automatically goes to background
Because NSTimer is not automatically paused, the nodes will continue with spawning. So you have to take an additional step and invalidate/restart timer by your self. When using SKAction, this is done automatically. There are some other flaws of using NSTimer in SpriteKit, search SO about all that, there are some posts which covering all this.
import SpriteKit
class GameScene: SKScene{
var radius:UInt32 = 0
override func didMoveToView(view: SKView) {
startSpawning()
}
func startSpawning(){
let wait = SKAction.waitForDuration(0.5)
// let wait = SKAction.waitForDuration(1, withRange: 0.4) // randomize wait duration
let addNode = SKAction.runBlock({
[unowned self] in //http://stackoverflow.com/a/24320474/3402095 - read about strong reference cycles here
if(self.radius >= 30){
if self.actionForKey("spawning") != nil {
self.removeActionForKey("spawning")
}
}
self.radius++
let sprite = self.spawnNode()
sprite.position = CGPoint(x: Int(arc4random()) % 300, y: Int(arc4random()) % 300) // change this to randomize sprite's position to suit your needs
self.addChild(sprite)
})
//wait & add node
let sequence = SKAction.sequence([wait, addNode])
//repeat forever
runAction(SKAction.repeatActionForever(sequence), withKey: "spawning")
}
func spawnNode()->SKSpriteNode{
let sprite = SKSpriteNode(color: SKColor.purpleColor(), size: CGSize(width: 50, height: 50))
//Do sprite initialization here
return sprite
}
}
The sleep stops the whole app because you are running the loop on the main thread.
You can solve this problem in one of two ways...
1) Use an NSTimer. Set it to the amount of time you want to delay. Put the body of the loop in the timer's trigger function and disable the timer when it has been called enough times. This is the best solution.
2) Wrap the loop in a dispatch async block to a background thread and put a sleep in the loop. If you do this though, you will have to wrap the UI code in another dispatch async block that comes back to the main thread.

Waiting for asynchronous calls in a swift script

Im writing a swift script to be run in terminal that dispatches to the background thread a couple of operations. Without any extra effort, after all my dispatching is done, the code reaches the end of the file and quits, killing my background operations as well. What is the best way to keep the swift script alive until my background operations are finished?
The best I have come up with is the following, but I do not believe this is the best way, or even correct.
var semaphores = [dispatch_semaphore_t]()
while x {
var semaphore = dispatch_semaphore_create(0)
semaphores.append(semaphore)
dispatch_background {
//do lengthy operation
dispatch_semaphore_signal(semaphore)
}
}
for semaphore in semaphores {
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
}
In addition to using dispatch_groups, you can also do the following:
yourAsyncTask(completion: {
exit(0)
})
RunLoop.main.run()
Some resources:
RunLoop docs
Example from the swift-sh project
Exit code meanings
Thanks to Aaron Brager, who linked to
Multiple workers in Swift Command Line Tool ,
which is what I used to find my answer, using dispatch_groups to solve the problem.
How about something like this:
func runThingsInTheBackground() {
var semaphores = [dispatch_semaphore_t]()
for delay in [2, 3, 10, 7] {
var semaphore = dispatch_semaphore_create(0)
semaphores.append(semaphore)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) {
sleep(UInt32(delay))
println("Task took \(delay) seconds")
dispatch_semaphore_signal(semaphore)
}
}
for semaphore in semaphores {
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
}
}
This is very similar to what you have. My work 'queue' is an array of seconds to sleep, so that you can see that things are happening int he background.
Do note that this just runs all the tasks in the background. If you want to limit the number of active tasks to for example the number of CPU cores then you have to do a little more work.
Not sure if that is what you were looking for, let me know.