SIGABRT error when using NSTimer, Swift 2 Xcode 7 - ios

I have a function that flashes a button. The function is inside a for i loop, which is in the viewDidLoad function. I also have an NSTimer that calls the function repeatedly flashing a different button each time. However I am getting a SIGABRT error when I run this. If you are going to ask, I have made sure that the connections with my buttons are solid, no cut off connections.
var computerChoices = [Int](count: 11, repeatedValue: 0)
var randomIndex = 0
var pcChoice = 0
var lit = [b0o,b1o,b2o,b3o,b4o,b5o,b6o,b7o,b8o]
var litIndex = 0
override func viewDidLoad() {
super.viewDidLoad()
for i in 1...10{
print(randomIndex)
print(computerChoices)
var buttonChoice = lit[randomIndex]
randomIndex = Int(arc4random_uniform(UInt32(lit.count)))
computerChoices[i] = randomIndex
print("yoyoyo")
func flashingButtons(){
var one = computerChoices[pcChoice]
lit[one].setImage(UIImage(named: "redb.png"), forState: UIControlState.Normal)
pcChoice += 1
}
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("flashingButtons"), userInfo: nil, repeats: true)
}
}

Put out the flashingButtons function out of the viewDidLoad. The timer find the function and couldn't find it if it is embedded.
override func viewDidLoad() {
super.viewDidLoad()
for i in 1...10{
print(randomIndex)
print(computerChoices)
var buttonChoice = lit[randomIndex]
randomIndex = Int(arc4random_uniform(UInt32(lit.count)))
computerChoices[i] = randomIndex
print("yoyoyo")
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("flashingButtons"), userInfo: nil, repeats: true)
}
}
func flashingButtons(){
var one = computerChoices[pcChoice]
lit[one].setImage(UIImage(named: "redb.png"), forState: UIControlState.Normal)
pcChoice += 1
}

You should put flashingButtons() out side viewDidLoad. And in it you make sure that out of range don't happen because pcChoice increase over time.
func flashingButtons(){
var one = computerChoices[pcChoice]
lit[one].setImage(UIImage(named: "redb.png"), forState: UIControlState.Normal)
if pcChoice >= 10 {
pcChoice = 0
return
}
pcChoice += 1
}

Related

All digits not shown in timer countdown

While coming to a view I call a function to load a timer like so...
var count = 10
func startTimer() {
timer = Timer.scheduledTimer(timeInterval: 0.4, target: self, selector: #selector(self.update), userInfo: nil, repeats: true)
}
and update function is given as..
#objc func update() {
while (count != 0) {
count -= 1
countdownLabel.text = "\(count)"
}
timer.invalidate()
}
But what happens is when I come to this view, straightaway the number 0 is shown as opposed to ideally displaying all numbers in the sequence 9,8,7,6,5,4,3,2,1,0
What am I doing wrong here..?
Swift 4:
var totalTime = 10
var countdownTimer: Timer!
#IBOutlet weak var timeLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
startTimer()
}
This method call initializes the timer. It specifies the timeInterval (how often the a method will be called) and the selector (the method being called).
The interval is measured seconds so for it to perform like a standard clock we should set this argument to 1.
func startTimer() {
countdownTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(updateTime), userInfo: nil, repeats: true)
}
// Stops the timer from ever firing again and requests its removal from its run loop.
func endTimer() {
countdownTimer.invalidate()
}
//updateTimer is the name of the method that will be called at each second. This method will update the label
#objc func updateTime() {
timeLabel.text = "\(totalTime)"
if totalTime != 0 {
totalTime -= 1
} else {
endTimer()
}
}

How to change images cross dissolve xcode 9?

I want to changes background images in a nice way like cross dissolve...
I manage to let the image change within 3 seconds.
Can you help me with a code to let it change in a nice way?
var timer = Timer()
var counter = 0
#IBOutlet weak var imageBG: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
repated()
}
func repated() {
timer = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(ViewController.updatecounter), userInfo: nil, repeats: true)
}
#objc func updatecounter() {
counter += 1
if counter == 14 {
counter = 1
}
imageBG.image = UIImage(named: "\(counter).png")
}
Into your upodatecounter you can use an UIView transition like this:
#objc func updatecounter() {
counter += 1
if counter == 14 {
counter = 1
}
UIView.transition(with: imageBG,
duration:3.0,
options: .transitionCrossDissolve,
animations: { self.imageBG?.image = UIImage(named: "\(counter).png") },
completion: nil)
}

Long Press Recognize Gesture via Button - Swift 3

I'm new to Swift and I'm trying to make timer(in the label) that starts with a long press on the button. At the same time I want to change the long press button image when press the long press button. I leave button, I want the button revert back.
What might be wrong?
#IBOutlet weak var myBtn: UIButton!
func initGesture()
{
{ let longGesture = UILongPressGestureRecognizer(target: self, action: #selector(longTap(_:)))
myBtn.addGestureRecognizer(longGesture)
}
}
func TimerAction()
{
Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(longTap), userInfo: nil, repeats: false)
myBtn.setImage(UIImage(named: "xxx.png"), for: .normal)
}
#IBOutlet weak var lbl: UILabel!
func start()
{
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(ViewController2.updateTime as (ViewController2) -> () -> ())), userInfo: nil, repeats: true)
}
func updateTimer () {
count += 1
let hours = Int(count) / 3600
let minutes = Int(count) / 60 % 60
let seconds = Int(count) % 60
label.text = String(format: "%02i:%02i:%02i",hours,minutes,seconds)
}
func reset()
{
timer.invalidate()
count = 0
label.text = "00:00:00"
}
You can get TouchUpInside and TouchUpOutside also TouchDown action of button don't use the gesture.
class ViewController: UIViewController {
#IBOutlet weak var lbl: UILabel!
#IBOutlet weak var myBtn: UIButton!
var timer: NSTimer!
override func viewDidLoad() {
super.viewDidLoad()
myBtn.addTarget(self, action: "buttonDown:", forControlEvents: .TouchDown)
myBtn.addTarget(self, action: "buttonUp:", forControlEvents: [.TouchUpInside, .TouchUpOutside])
}
func buttonDown(sender: AnyObject) {
singleFire()
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "rapidFire", userInfo: nil, repeats: true)
}
func buttonUp(sender: AnyObject) {
timer.invalidate()
count = 0
label.text = "00:00:00"
}
func singleFire() {
myBtn.setImage(UIImage(named: "xxx.png"), for: .normal)
}
func rapidFire() {
count += 1
let hours = Int(count) / 3600
let minutes = Int(count) / 60 % 60
let seconds = Int(count) % 60
label.text = String(format: "%02i:%02i:%02i",hours,minutes,seconds)
}
}
You should implement button events instead of using the gesture recognisers here. The button events i talk about are TouchDown and TouchUpInside. TouchDown will tell you when a button is being pressed and touchupinside will tell you when the user lifted their finger from button.
So you will change the button image and start your timer on touchdown event. Then you will revert back on touchupinside event.
https://developer.apple.com/documentation/uikit/uicontrolevents
Try this,
set first the image of the button depending on its state.
self.arrowIcon.setImage(UIImage(named: "normalImage.png"), for: .normal)
self.arrowIcon.setImage(UIImage(named: "pressedImage.png"), for: .highlighted)

NSTimer: Trying to create multiple timers with one start and one stop button

I'm trying to create a simple countdown/Up timer app for myself. So far I've figured out how to create the timers which can count up and down with a start, stop and reset buttons but I can not create a multiple timer, I'm guessing its to do with the way I'm calling the function. I'm only guessing as its my first go at it.
Variables and Labels
var timerCountUp = 0
var timerCountDown = 45
var timerRunning = false
var timer = NSTimer()
#IBOutlet weak var timerUpLabel: UILabel!
func CountingUp(){
timerCountUp += 1
timerUpLabel.text = "\(timerCountUp)"
}
#IBOutlet weak var timerDownLabel: UILabel!
func CountingDown(){
timerCountDown -= 1
timerDownLabel.text = "\(timerCountDown)"
}
Stop and Rest Buttons
#IBAction func stopButton(sender: UIButton) {
if timerRunning == true{
timer.invalidate()
timerRunning = false
}
}
#IBAction func restartButton(sender: UIButton) {
timerCountUp = 0
timerUpLabel.text = "0"
}
For my start button I have the following
#IBAction func startButton(sender: UIButton) {
if timerRunning == false{
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("CountingUp"), userInfo: nil, repeats: true)
timerRunning = true
}
If my selector is either "CountingUp" or "CountingDown" I get one of them to work, so I did a bit of searching and came up with the following which does not work
#IBAction func startButton(sender: UIButton) {
if timerRunning == false{
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("timerStarted"), userInfo: nil, repeats: true)
timerRunning = true
}
func timerStarted() {
CountingUp()
CountingDown()
}
}
Would it be possible to show me where I have gone wrong please?

How can I make a function execute every second in swift?

I want to add a score to the top of my scene in the game I am working on. The score is going to based on how long you last, and will increase every second. Thanks for the help in advance!
import SpriteKit
class easyScene: SKScene {
let scrollBarEasyBottom = SKSpriteNode(imageNamed: "scrollBarEasyBottom")
let scrollBarEasyTop = SKSpriteNode(imageNamed: "scrollBarEasyTop")
let ball = SKSpriteNode(imageNamed: "ball")
var origSBEBpositionX = CGFloat(0)
var origSBETpositionX = CGFloat(0)
var maxSBEBX = CGFloat(0)
var SBEBSpeed = 5
var maxSBETX = CGFloat(0)
var SBETSpeed = 5
var score = 0
var timer: NSTimer?
var scoreText = SKLabelNode(fontNamed: "Kailasa")
override func didMoveToView(view: SKView) {
println("Easy Scene is the location")
self.backgroundColor = UIColor.blackColor()
self.scrollBarEasyBottom.position = CGPoint(x:0, y:270)
self.addChild(self.scrollBarEasyBottom)
self.scrollBarEasyBottom.yScale = 0.2
self.origSBEBpositionX = self.scrollBarEasyBottom.position.x
// end scrollBarEasyBottom
self.scrollBarEasyTop.position = CGPoint(x:20, y:400)
self.addChild(self.scrollBarEasyTop)
self.scrollBarEasyTop.yScale = 0.2
self.origSBETpositionX = self.scrollBarEasyTop.position.x
// end scrollBarEasyTop
self.ball.position = CGPoint(x:40, y:293)
self.addChild(self.ball)
self.ball.yScale = 0.17
self.ball.xScale = 0.17
// end ball
self.maxSBEBX = self.scrollBarEasyBottom.size.width - self.frame.size.width
self.maxSBEBX *= -1
self.maxSBETX = self.scrollBarEasyTop.size.width - self.frame.size.width
self.maxSBETX *= -1
//
self.scoreText.text = "0"
self.scoreText.fontSize = 60
self.scoreText.position = CGPoint(x: CGRectGetMidX(self.frame), y: 500)
self.scoreText.text = String(self.score)
self.addChild(self.scoreText)
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("scoreIncrease") , userInfo: nil, repeats: true)
func scoreIncrease (){
score++
println(score)
}
}
override func update(currentTime: NSTimeInterval) {
if self.scrollBarEasyBottom.position.x <= maxSBEBX + 1200 {
self.scrollBarEasyBottom.position.x = self.origSBEBpositionX
}
if self.scrollBarEasyTop.position.x <= maxSBETX + 1200 {
self.scrollBarEasyTop.position.x = self.origSBETpositionX
}
scrollBarEasyBottom.position.x -= CGFloat(self.SBEBSpeed)
scrollBarEasyTop.position.x -= CGFloat(self.SBETSpeed)
// moving bars
var degreeRotation = CDouble(self.SBEBSpeed) * M_PI / 180
self.ball.zRotation -= CGFloat(degreeRotation)
//rotate ball
}
}
After running this code, I always get an
unrecognized selector sent to instance error
You can use one like this:
var timer = NSTimer()
override func viewDidLoad() {
scheduledTimerWithTimeInterval()
}
func scheduledTimerWithTimeInterval(){
// Scheduling timer to Call the function "updateCounting" with the interval of 1 seconds
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("updateCounting"), userInfo: nil, repeats: true)
}
func updateCounting(){
NSLog("counting..")
}
Swift 3:
var timer = Timer()
override func viewDidLoad() { // Use for the app's interface
scheduledTimerWithTimeInterval()
}
override func didMove(to view: SKView) { // As part of a game
scheduledTimerWithTimeInterval()
}
func scheduledTimerWithTimeInterval(){
// Scheduling timer to Call the function "updateCounting" with the interval of 1 seconds
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(self.updateCounting), userInfo: nil, repeats: true)
}
#objc func updateCounting(){
NSLog("counting..")
}
Swift 5:
Note: this solution is compatible with iOS 10.0+.
// If needing to check for iOS compatibility use
// if #available(iOS 10.0, *) {code}
var timer = Timer()
override func viewDidLoad() {
self.timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { _ in
updateCounting()
})
}
func updateCounting(){
print("counting...")
}
You can then invalidate (stop) the timer using:
timer.invalidate()
There is something called NSTimer in swift which could solve your problem. I have given an example like how you can use it. Just customise it for your purpose.
var timer = NSTimer.scheduledTimerWithTimeInterval(1.0,
target: self,
selector: Selector("yourMethodToCall"),
userInfo: nil,
repeats: true)
Add this line to the place where you need to call your function repeatedly.
The 1.0 refers to 1 second.
Change the selector to call yourMethodName
repeats is set to true to call that function every second.
Try this out and let me know if your are stuck somewhere. Thanks.
Swift 3
find this solution it worked for me
weak var timer: Timer?
var timerDispatchSourceTimer : DispatchSourceTimer?
func startTimer() {
if #available(iOS 10.0, *) {
timer = Timer.scheduledTimer(withTimeInterval: 3, repeats: true) { [weak self] _ in
// do something here
}
} else {
// Fallback on earlier versions
timerDispatchSourceTimer = DispatchSource.makeTimerSource(flags: [], queue: DispatchQueue.main)
timerDispatchSourceTimer?.scheduleRepeating(deadline: .now(), interval: .seconds(60))
timerDispatchSourceTimer?.setEventHandler{
// do something here
}
timerDispatchSourceTimer?.resume()
}
}
func stopTimer() {
timer?.invalidate()
//timerDispatchSourceTimer?.suspend() // if you want to suspend timer
timerDispatchSourceTimer?.cancel()
}
// if appropriate, make sure to stop your timer in `deinit`
deinit {
stopTimer()
}
I prefer
var timer: Timer?
override func viewDidLoad() {
super.viewDidLoad()
timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { (timer) in
// Do what you need to do repeatedly
}
}
To stop it:
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if timer != nil {
timer?.invalidate()
timer = nil
}
}
Xcode 10.2 Swift 5:
override func viewDidLoad() {
super.viewDidLoad()
// ...
Timer.scheduledTimer(timeInterval: 8.0, target: self, selector: Selector(("your #obcj func name")), userInfo: nil, repeats: true)
}
//Anywhere in the same view controller to stop the loop:
Timer.cancelPreviousPerformRequests(withTarget: your #obcj func name())
I don't think you need NSTimer for this.
Since you are using SpriteKit, I am going to suggest simplest solution in my opinion:
Declare a variable var prevScoreCalcTime:TimeInterval = 0
Inside of update func in your GameScene set it up like below:
override func update(_ currentTime: TimeInterval) {
if currentTime - prevScoreCalcTime > 1 {
prevScoreCalcTime = currentTime
// Any function you put here will execute every second
}
}
Good luck!
// For running a piece of code every second
///Runs every second, to cancel use: timer.invalidate()
#discardableResult public static func runThisEvery(
seconds: TimeInterval,
startAfterSeconds: TimeInterval,
handler: #escaping (CFRunLoopTimer?) -> Void) -> Timer {
let fireDate = startAfterSeconds + CFAbsoluteTimeGetCurrent()
let timer = CFRunLoopTimerCreateWithHandler(kCFAllocatorDefault, fireDate, seconds, 0, 0, handler)
CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, CFRunLoopMode.commonModes)
return timer!
}

Resources