Changing the interval of a timer in an if statement
You could do what you want as follows:
First declare 2 properties (in your class but outside all the function definitions)
var timeOfLastSpawn: CFTimeInterval = 0.0
var timePerSpawn: CFTimeInterval = 1.0
Then, in Update
, check to see if the timePerSpawn has been exceeded. If so, call your spawn process which spawns new objects and then reset the time since the last spawn:
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
if (currentTime - timeOfLastSpawn > timePerSpawn) {
spawnObject()
self.timeOfLastSpawn = currentTime
}
}
func spawnObject() {
// Your spawn code here
}
The advantage of making the spawn process a separate function is that you can call it from didMoveToView
or any other place to spawn objects outside of the normal time-controlled cycle.
You can change the value of timePerSpawn
as necessary to control the rate at which objects are spawned.
You could also look into creating an SKAction
that runs spawnObject
at specified time intervals, but I think to change the rate at which objects are spawned, you'll have to delete and re-create the SKAction, but your could do this in a setter for timePerSpawn.
You shouldn't really use NSTimer is SpriteKit, as the SpriteKit engine will be unaware of what the timer is doing and can't control it (one example is that the timer keeps running if the set the scene to paused).
How do I change timing for NSTimer?
Sure you can do this. Change repeats:YES
to repeats:NO
so that the timer doesn't repeat, and then in onTimer
, just start a new timer with a longer interval. You need a variable to hold your interval so that you can make it a bit longer each time through onTimer
. Also, you probably don't need to retain the timer anymore, as it will only fire once, and when it does, you'll get a new timer.
I'm no Objective-C expert (or iOS expert...) and it's been a while but I think something like this:
float gap = 0.50;
[NSTimer scheduledTimerWithTimeInterval:gap target:self selector:@selector(onTimer) userInfo:nil repeats:NO];
-(void) onTimer {
gap = gap + .05;
[NSTimer scheduledTimerWithTimeInterval:gap target:self selector:@selector(onTimer) userInfo:nil repeats:NO];
}
Something like that? Oh, and I'm really not too sure about the retain
semantics here... read the docs to make sure you don't leak!
How does one change/update the time interval in an NSTimer?
You can't. Invalidate the timer, and create a new one with a different time interval.
You can change the fire time. So if you want to change the time interval after the first firing only, create the timer with that time interval, then change the firing time so that the timer is fired the first time at the time you want.
Change NSTimer interval after a certain number of fires
Make the timer object a member variable. Initially set animation time as 1 second. In the callback invalidate the timer and create a new one with 1 or 4 seconds depending on the counter.
@interface ViewController ()
@property (strong,nonatomic) NSMutableArray *images;
@property (strong,nonatomic) UIImageView *animationImageView;
{
NSTimer *_timer;
}
@end
@implementation ViewController {
NSInteger counter;
}
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *imageNames = @[@"hello.png",@"bye.png",@"helloagain.png",@"bye again"];
self.images = [[NSMutableArray alloc] init];
for (int i = 0; i < imageNames.count; i++) {
[self.images addObject:[UIImage imageNamed:[imageNames objectAtIndex:i]]];
}
self.animationImageView = [[UIImageView alloc] initWithFrame:CGRectMake(60, 95, 86, 90)];
self.animationImageView.image = self.images[0];
[self.view addSubview:self.animationImageView];
self.animationImageView.userInteractionEnabled = TRUE;
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(bannerTapped:)];
singleTap.numberOfTapsRequired = 1;
singleTap.numberOfTouchesRequired = 1;
[self.animationImageView addGestureRecognizer:singleTap];
_timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(changeImage:) userInfo:nil repeats:YES];
}
-(void)changeImage:(NSTimer *) timer {
[_timer invalidate];
if (counter == self.images.count - 1 ) {
counter = 0;
}else {
counter ++;
}
if(counter == 0 || counter == 1)
{
_timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(changeImage:) userInfo:nil repeats:YES];
}
else if(counter == 2 || counter == 3)
{
_timer = [NSTimer scheduledTimerWithTimeInterval:4 target:self selector:@selector(changeImage:) userInfo:nil repeats:YES];
}
self.animationImageView.image = self.images[counter];
}
Set a timer with variable intervals in swift
Here is a basic idea on how to approach the problem
struct RequestMananger {
var timers: [Timer] = []
mutating func startSequence() {
var delay = 10.0
sendRequest()
timers.append(scheduleTimer(delay))
delay += 20
timers.append(scheduleTimer(delay))
delay += 40
timers.append(scheduleTimer(delay))
delay += 60
timers.append(scheduleTimer(delay, repeats: true))
}
private func scheduleTimer(_ delay: TimeInterval, repeats: Bool = false) -> Timer {
return Timer.scheduledTimer(withTimeInterval: delay, repeats: false, block: { timer in
self.sendRequest()
})
}
func sendRequest() {
}
func cancelTimers() {
timers.forEach { $0.invalidate() }
}
}
How can I use Timer (formerly NSTimer) in Swift?
This will work:
override func viewDidLoad() {
super.viewDidLoad()
// Swift block syntax (iOS 10+)
let timer = Timer(timeInterval: 0.4, repeats: true) { _ in print("Done!") }
// Swift >=3 selector syntax
let timer = Timer.scheduledTimer(timeInterval: 0.4, target: self, selector: #selector(self.update), userInfo: nil, repeats: true)
// Swift 2.2 selector syntax
let timer = NSTimer.scheduledTimerWithTimeInterval(0.4, target: self, selector: #selector(MyClass.update), userInfo: nil, repeats: true)
// Swift <2.2 selector syntax
let timer = NSTimer.scheduledTimerWithTimeInterval(0.4, target: self, selector: "update", userInfo: nil, repeats: true)
}
// must be internal or public.
@objc func update() {
// Something cool
}
For Swift 4, the method of which you want to get the selector must be exposed to Objective-C, thus @objc
attribute must be added to the method declaration.
iOS: How to call a function sequentially after different (defined) amount of time?
There are multiple things wrong here:
Selector(executeCustomScheduler(nextTimeIndex))
creates a selector based on the return value of executingexecuteCustomScheduler(nextTimeIndex)
one timewithObject: self
- why would you passself
?- why are you using
performSelector
at all? executionTimes
is not in milliseconds but in seconds, or at least the method expects them to be- final problem: your argument is a primitive Int which gets really troublesome when passing it around in the
performSelector
Solutions:
Selector("executeCustomScheduler:")
is the correct selectornextTimeIndex
is the correct argument to pass along- it would probably be better to use something that has a bit more type security, anything with selectors is wide open to a ton of problems regarding renaming e.g.
- divide the values by 1000 before passing them into the
performSelector
- I do not really have a good solution: the easiest and probably worst one: use a
String
instead of anInt
:/
Better solution:
Use dispatch_after
, get rid of those pesky selectors and be typesafe all the way through:
class Obj {
let executionTimes = [0, 1500, 3500, 4700]
func executeCustomScheduler(timeIndex: Int) {
NSLog("Hello")
let time = executionTimes[timeIndex]
let nextTimeIndex = (timeIndex + 1) % executionTimes.count
let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(Double(time) / 1000 * Double(NSEC_PER_SEC)))
dispatch_after(delayTime, dispatch_get_main_queue()) {
self.executeCustomScheduler(nextTimeIndex)
}
}
}
let obj = Obj()
obj.executeCustomScheduler(0)
Metronome SwiftUI, Change timer interval whenever the @State var is changed
The easiest way to perform code when a @State
value changes is to add an onChange
modifier to a child view of the view where you defined your @State
, e.g.:
struct ContentView: View {
@State private var period: Double = 0.5
var body: some View {
Slider(value: period, in: 0.25...5, step: 0.25)
.onChange(of: period) { newValue in
// perform your code here
}
}
}
See also Apple's documentation and an example on Hacking With Swift.
Related Topics
Connecting Avaudiosourcenode to Avaudiosinknode Does Not Work
Alamofire Nonblocking Connection
Hit Fatal Error: Unexpectedly Found Nil While Unwrapping an Optional Value (Lldb)
Communication Error When Uploading 90 Mb IPA File with Swift to Appstore
Weird Behaviour in Swiftui+Combine When Class -> Struct
How to Custom The Image of Mkannotation Pin
Why Extensions Cannot Add Stored Properties
Swift Coredata: Unable to Section Tableview Using Sectionnamekeypath with Custom Function
Uipageviewcontroller with Previous and Next Buttons
How to Name File Stored to Files App via Uactivityviewcontroller
Change The 2Nd and 3Rd Pickerview Acording to What Row from The 1St Picker Is Selected
Using UIscrollview Correctly in Swiftui
How to Access Camera with Swiping Gesture
How to Highlight a Custom UIbutton That Has No Text or Background
Uibutton State Changing While Scrolling The Tableview with Multiple Sections - Swift