Im creating a simple typing app with timer. The timer should be in a form of a progress bar that decrements every second.
To implement the progressbar, I intended to set the progress to 0.1 lesser to the current progress every 1 second. But there is an "Unrecognized selector for instance " error when i set the progress.
Is there any other way to work around.
import Foundation
import UIKit
class TestView: UIViewController, UITextInputTraits {
#IBOutlet weak var TestLabel: UILabel!
#IBOutlet weak var TypingField: UITextField!
#IBOutlet weak var progressView: UIProgressView!
var time : Float = 0.0
var timer: NSTimer!
var test = 0;
var progress : Float = 1
var myMutableString = NSMutableAttributedString()
var testStringArray = ["abode" , "tutorial" , "completed",
"war", "method", "continue",
"machine", "texting" , "iterate"]
var idx = 0;
var setProg : Float = 1
func textFieldDidChange(textField: UITextField) {
let s = TypingField.text!
if(s.characters.last == " "){
let word = s.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet())
if(!word.isEmpty){
print(testStringArray[idx])
if(word == testStringArray[idx]){
idx++;
TypingField.text = "";
TestLabel.text = testStringArray[idx];
}else{
TypingField.text = "";
}
}
}
}
func setProgress() {
setProg -= 0.1
progressView.progress = setProg <-- cannot decrement progress bar
}
override func viewDidLoad() {
super.viewDidLoad()
TypingField.autocorrectionType = .No
TypingField.autocapitalizationType = .None
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector:Selector("setProgress"), userInfo: nil, repeats: true)
TestLabel.text = testStringArray[idx];
TypingField.addTarget(self, action: "textFieldDidChange:", forControlEvents: UIControlEvents.EditingChanged)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
You have coded scheduledTimerWithTimeInterval in a manner like it is done with Objective-C. In Swift it is done differently. Instead of:
selector:Selector("setProgress")
just use:
selector:"setProgress"
Change the function declaration for func setProgress() to:
func setProgress(sender: NSTimer)
And change Selector("setProgress") to "setProgress:"
EDIT:
Apparently the method setProgress already exists, so you'll need to rename the function, e.g. to setProgressBar or something to that effect.
Method 'setProgress' with Objective-C selector 'setProgress:' conflicts with setter for 'progress' with the same Objective-C selector
I think the error was fix when I delete and recreate the progressbar.. it may have been as MikeG suggested about incorrect connection on the outlet. Anyways thanks all for your help..
Related
I couldn't figure out how to copy value of variable into another variable in Swift, an example code for this in python would be
def assignVariable():
x=1
y=x
return y
RESULT 1
When I did this it doesn't seem to work in Swift. Is there any solution to this or am I doing something wrong?
Edit: problem is at
var originalCount=countDown
it gave me Use of unresolved identifier 'countDown' but when I assign it literally it works. Here's my swift code
import Cocoa
class MainWindow: NSWindowController {
var hitCount = 0
var started:Bool = false
var timer = 10
var colorList: [NSColor] = [ NSColor.black,NSColor.blue,NSColor.brown,NSColor.cyan,NSColor.darkGray,NSColor.gray,NSColor.green,NSColor.lightGray,NSColor.magenta,NSColor.orange,NSColor.purple,NSColor.red,NSColor.white,NSColor.yellow]
#IBOutlet weak var button1: NSButton!
#IBOutlet weak var scrubber1: NSScrubber!
#IBOutlet weak var display: NSTextField!
override func windowDidLoad() {
super.windowDidLoad()
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
}
var countdown=10
var originalCount=countDown
//(countdown,originalCount) = (10,10) //it works if i use this instead
func startGame(){
if(countDown>0 || started==true){
display.stringValue=String(countDown)
countDown-=1
let seconds = 1.0
DispatchQueue.main.asyncAfter(deadline: .now() + seconds) {
self.startGame()
}
}else{
display.stringValue="Done "+String(hitCount)+" Taps in " + String(originalCount) + "Tap to RESET"
started=false
countDown=10;
}
}
#IBAction func labelPress(_ sender: Any) {
display.stringValue="__RESET__"
hitCount=0
countDown=10
started=false
}
#IBAction func buttonPressed(_ sender: Any) {
if started==false{
startGame()
}
button1.bezelColor = colorList[Int.random(in: 0..<colorList.count)]
started=true
button1.title=String(hitCount)
hitCount+=1
}
}
You can't initialise one variable with another at the top level in your class. Looking at your code I don't think that originalCount needs to be a property, move it inside startGame() instead and make it a local variable and also use let since it isn't changing
var countdown=10
func startGame(){
let originalCount = countDown
if(countDown>0 || started==true){
...
}
I'm using Swift 5 in Xcode to code an app. On one view controller, I am creating a timer, which counts from 20 minutes down to 0. I have what I think is a successful code, but it throws back one error. In the line
timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(SkippingViewController.updateTimer), userInfo: nil, repeats: true)
it gives an error saying Type 'SkippingViewController' has no member 'updateTimer' (SkippingViewController is the name of the view controller for the page of the app my timer is on)
How can I resolve this issue?
import UIKit
class SkippingViewController: UIViewController {
#IBOutlet weak var timeLabel: UILabel!
#IBOutlet weak var startWorkoutButton: UIButton!
#IBOutlet weak var pauseWorkoutButton: UIButton!
var timer = Timer()
var counter = 20.00
var isRunning = false
override func viewDidLoad() {
super.viewDidLoad()
timeLabel.text = "\(counter)"
startWorkoutButton.isEnabled = true
pauseWorkoutButton.isEnabled = false
// Do any additional setup after loading the view.
}
#IBAction func startWorkoutButtonDidTouch(_ sender: Any) {
if !isRunning {
timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(SkippingViewController.updateTimer), userInfo: nil, repeats: true)
startWorkoutButton.isEnabled = false
pauseWorkoutButton.isEnabled = true
isRunning = true
}
}
#IBAction func pauseWorkoutButtonDidTouch(_ sender: Any) {
func updateTimer() {
counter -= 0.01
timeLabel.text = String(format: "%.01f", counter)
}
}
}
Your problem is, that there is no method called 'updateTimer' in SkippingViewController.swift. You falsely put the method inside of the method 'pauseWorkoutButtonDidTouch'. In order to resolve the error insert the following code into SkippingViewController.swift:
#objc func updateTimer() {
counter -= 0.01
timeLabel.text = String(format: "%.01f", counter)
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
class ThirdViewController: UIViewController {
var i = 3
var a: Double = 0
var fastestScore:Float = 100000000000000.0
var randomNumberX = Int(arc4random_uniform(375))
var randomNumberY = Int(arc4random_uniform(667))
#IBOutlet weak var fastestScoreLabel: UILabel!
#IBOutlet weak var homeButtonLabel: UIButton!
#IBOutlet weak var finalLabel: UILabel!
#IBOutlet weak var playAgainButtonLabel: UIButton!
#IBOutlet weak var circleImage: UIButton!
#IBOutlet weak var secondTimerLabel: UILabel!
#IBOutlet weak var counterLabel: UILabel!
var timerA = Timer()
var timerB = Timer()
#IBAction func homeButton(_ sender: Any) {
nextPage = false
}
#IBAction func playAgainButton(_ sender: Any) {
randomNumberX = Int(arc4random_uniform(375))
randomNumberY = Int(arc4random_uniform(667))
homeButtonLabel.isHidden = true
counterLabel.text = "3"
i = 3
timerA = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(ThirdViewController.counterFunc), userInfo: nil, repeats: true)
a = 0
counterLabel.isHidden = false
playAgainButtonLabel.isHidden = true
circleImage.isHidden = true
finalLabel.isHidden = true
secondTimerLabel.isHidden = true
fastestScoreLabel.isHidden = true
}
#IBAction func circleButton(_ sender: Any) {
fastestScoreLabel.isHidden = false
circleImage.isHidden = true
homeButtonLabel.isHidden = false
timerB.invalidate()
playAgainButtonLabel.isHidden = false
var saying = ""
if a < 0.2 {
saying = "That's actually pretty good \(a) seconds is pretty fast"
} else if a >= 0.2 && a <= 0.45 {
saying = "\(a) seconds is not really that good"
} else {
saying = "\(a) seconds? Seriously? Are you even trying?"
}
finalLabel.text = saying
finalLabel.isHidden = false
if Float(a) < fastestScore {
fastestScore = Float(a)
UserDefaults.standard.set(fastestScore, forKey: "Fastest Score")
let savedFastestScore = UserDefaults.standard.float(forKey: "Fastest Score")
fastestScoreLabel.text = String(savedFastestScore)
}
}
func secondTimer() {
a = a + 0.01
secondTimerLabel.text = String(a)
}
func counterFunc() {
if i > 1 {
i -= 1
counterLabel.text = String(i)
} else {
timerB = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(ThirdViewController.secondTimer), userInfo: nil, repeats: true)
circleImage.isHidden = false
self.circleImage.center = CGPoint(x:randomNumberX, y:randomNumberY)
counterLabel.isHidden = true
timerA.invalidate()
secondTimerLabel.isHidden = false
}
}
override func viewDidLoad() {
super.viewDidLoad()
fastestScoreLabel.isHidden = true
homeButtonLabel.isHidden = true
playAgainButtonLabel.isHidden = true
circleImage.isHidden = true
secondTimerLabel.isHidden = true
timerA = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(ThirdViewController.counterFunc), userInfo: nil, repeats: true)
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
I have tried many different times using userDefaults to try and save the highscore when you close out but I just can't seem to do it. If someone has any idea on how to do it I would really appreciate it lol.
You still haven't clearly explained what problem you're seeing, but my guess is that your high score doesn't appear to be saved across restarts of the app.
The problem is that you initialize fastestScore to 100000000000000.0 when your ThirdViewController is created. You don't load it from UserDefaults. Thus even if there is a stored fastestScore, you don't load it at launch.
You should fix this with two changes. First, in your application delegate, you should register a default high score:
let bestScoreKey = "bestScore"
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, willFinishLaunchingWithOptions options: [UIApplicationLaunchOptionsKey : Any]?) -> Bool {
UserDefaults.standard.register(defaults: [
bestScoreKey: 1_000_000_000.0
])
return true
}
}
You should also register any other default settings there.
Second, in ThirdViewController, you should initialize fastestScore from UserDefaults. You can also save changes back to UserDefaults in the property's didSet observer:
var fastestScore: Double = UserDefaults.standard.double(forKey: bestScoreKey) {
didSet {
UserDefaults.standard.set(fastestScore, forKey: bestScoreKey)
}
}
Other tips:
There is no reason to make fastestScore a Float if your scores are Double. Just save it as a Double.
Don't repeat string keys. The compiler won't catch your spelling errors. Put the key in a constant like I did with bestScoreKey.
You can use _ in long numbers to make them more readable.
Insulting your player is a questionable marketing strategy. How would you have felt if the first comment on your question was “Seriously? Are you even trying?”
When you are saving high scores, make sure that the current score you have is greater than the new score.
suppose the current high score is 100
var fastestScore = 100
var currentScore: Int?
if currentScore < fastestScore {
Userdefaults.standard.set(currentScore, forKey: "Fastest Score")
}
The code above will go to the function where you need to save the high score. Maybe in your game over scene.
To retrieve the low score, do this
var savedFastestScore = UserDefaults.standard.float(forKey: "Fastest Score")
i-m trying to learn how to code and working on my first ever app. it is some gym app. and i want to have a timer and a label to be changed after presing a button.
This is my code until now but i cant figure it out how to display the next label and the next timer to countdown after presing the button.
class _daysday1ViewController: UIViewController {
#IBOutlet weak var exerciseNameLabel: UILabel!
#IBOutlet weak var btnStart: UIButton!
#IBOutlet weak var exercisePicture: UIImageView!
#IBOutlet weak var exerciseDescriptionLabel: UILabel!
#IBOutlet weak var timerLabel: UILabel!
#IBAction func nextButtonTapped(sender: AnyObject) {
var timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("update"), userInfo: nil, repeats: true)
count = countList[0]
}
var exerciseIndex = 0
var exerciseList = ["12 reps at 80% of capicity" , " 10 reps at 90%" , "7 to 10 reps at full capacity"]
var countList = [4 , 6 ,8]
var count = 1
override func viewDidLoad() {
super.viewDidLoad()
}
func update() {
if(count >= 0) {
timerLabel.text = String(count--)
self.btnStart.enabled = false
return
}
btnStart.enabled = true
exerciseDescriptionLabel.text = exerciseList[0]
}
`
Your timer will go away almost as soon as it's created, because you declared the timer var within the nextButtonTapped function. That function finishes quickly, and your timer goes away when it finishes.
To fix this, declare the timer var at the class level, the same place you declared the count var, like this:
var timer: NSTimer?
Declaring it as an optional (?) allows it be nil until the next button is tapped.
To create it, simply change the line of code in nextButtonTapped to begin with this:
self.timer = ...
Instead of this:
var timer = ...
In your func nextButtonTapped() method, you can include the code for this. The #IBAction will make this method fire every time the button is touched, so if you need variables to change with this action simple outline what you want to change between the {};
example:
var currentExercise = 0
#IBAction func nextButtonTapped() {
btnStart.textLabel.text = "New Text To Display"
currentExercise += 1
exerciseDescriptionLabel.text = exerciseList[currentExercise]
}
I have a Progress view bar that I would like to use to indicate time. This is my first project in Swift, and I am unsure how to go about this. So any help/ advise would be appreciated ...
(Using Xcode 7.2 and Swift 2.0)
Below Is my view controller. When 'btnPlaySession' is triggered, the content on the view controller is changed every 20 seconds. While the timer is counting to 20, id like to indicate this with the progress bar (so the progress bar resets, each time the content changes).
class CreatedSessionViewController: UIViewController {
var createdSession: [YogaPose]!
var poseDuration: Double = 20.00
var timer = NSTimer!()
var currentPoseIndex = 1
//Outlets:
#IBOutlet var poseProgressView: UIProgressView!
#IBOutlet var lblPoseCount: UILabel!
#IBOutlet var lblPoseName: UILabel!
#IBOutlet var imgPose: UIImageView!
#IBOutlet var tvDescription: UITextView!
// Do any additional setup after loading the view:
override func viewDidLoad() {
super.viewDidLoad()
displayFirstPoseInArray()
}
func displayFirstPoseInArray(){
lblPoseCount.text = (String(currentPoseIndex) + "/" + String(createdSession.count))
lblPoseName.text = createdSession[0].title
imgPose.image = UIImage(named: String(format: "%d.jpg", (createdSession[0].id)!))
tvDescription.text = createdSession[0].desc
}
#IBAction func btnPlaySession(sender: AnyObject) {
timer = NSTimer.scheduledTimerWithTimeInterval(poseDuration, target: self, selector: "getNextPoseData", userInfo: nil, repeats: true)
}
func getNextPoseData(){
if (currentPoseIndex < createdSession.count){
setProgressBar()
lblPoseCount.text = (String(currentPoseIndex + 1) + "/" + String(createdSession.count))
lblPoseName.text = createdSession[currentPoseIndex].title
imgPose.image = UIImage(named: String(format: "%d.jpg",(createdSession[currentPoseIndex].id)!))
tvDescription.text = createdSession[currentPoseIndex].desc
currentPoseIndex += 1
print(currentPoseIndex)
}
}
func setProgressBar(){
}
}
OK - so if you want the progress bar to update every second, then you need a timer that fires every second - but which does it 20 times, and calls setProgressBar as selector instead of getNextPoseData
within setProgressBar, you need to increment a class-level attribute, indexProgressBar perhaps, and simply set the progress bar attribute progress to 1.0 / indexProgressBar
if indexProgressBar == 20, then call getNextPoseData, and reset your progress bar
and here's a simplified version of how you might do that
class ViewController: UIViewController
{
#IBOutlet weak var progressBar: UIProgressView!
var timer = NSTimer!()
var poseDuration = 20
var indexProgressBar = 0
var currentPoseIndex = 0
override func viewDidLoad()
{
super.viewDidLoad()
// initialise the display
progressBar.progress = 0.0
}
#IBAction func cmdGo(sender: AnyObject)
{
// display the first pose
getNextPoseData()
// start the timer
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "setProgressBar", userInfo: nil, repeats: true)
}
func getNextPoseData()
{
// do next pose stuff
currentPoseIndex += 1
print(currentPoseIndex)
}
func setProgressBar()
{
if indexProgressBar == poseDuration
{
getNextPoseData()
// reset the progress counter
indexProgressBar = 0
}
// update the display
// use poseDuration - 1 so that you display 20 steps of the the progress bar, from 0...19
progressBar.progress = Float(indexProgressBar) / Float(poseDuration - 1)
// increment the counter
indexProgressBar += 1
}
}
For Continues loader
func setProgress() {
time += 0.1
ProgressBar.setProgress(time / 3, animated: true)
if time >= 3 {
self.time = 0.01
ProgressBar.progress = 0
let color = self.downloadProgressBar.progressTintColor
self.downloadProgressBar.progressTintColor = self.downloadProgressBar.trackTintColor
self.downloadProgressBar.trackTintColor = color
}