Swift Multiples App running error - swift2

I have running an issue with the Multiples App. I was just trying out and see if I can get the function right. However, this app can only run once, the addition itself is correct but when the game starts over, it will throw an error. Please help ~~
class ViewController: UIViewController {
#IBOutlet weak var AddBtn: UIButton!
#IBOutlet weak var TextInput: UITextField!
#IBOutlet weak var ResultLabel: UILabel!
var CurrentNum = 0
var SecondNum = 0
let MaxNum = 30
func currentNumUpdate(sum: Int, Mul: Int, nSum: Int){
ResultLabel.text = "\(sum) + \(Mul) = \(nSum)"
}
#IBAction func AddtionBtn(sender: UIButton) {
let TotalSum = CurrentNum + SecondNum
currentNumUpdate(CurrentNum, Mul: SecondNum, nSum: TotalSum)
CurrentNum += SecondNum
if (TextInput != nil && TextInput != ""){
SecondNum = Int(TextInput.text!)!
}
if GameOver(){
GameStartOver()
}
}
func GameOver() -> Bool{
if (CurrentNum > MaxNum){
return true
}else {
return false
}
}
func GameStartOver(){
ResultLabel.hidden = false
TextInput.text = ""
AddBtn.hidden = false
ResultLabel.text = "Again"
}
}

Related

Use of local variable 'updateTimer' before its declaration Egg timer

I just started learning programming and the instructor asked us to make an egg timer app.
I tried to run her example solution but XCode shows an issue with the code at #selector(updateTimer). The error says Use of local variable 'updateTimer' before its declaration.
This is the code:
class ViewController: UIViewController {
#IBOutlet weak var progress: UILabel!
let eggTimes = ["Soft" :3, "Medium":4, "Hard":6]
var secondsRemaining = 60
var timer = Timer()
#IBAction func hardnessSelected(_ sender: UIButton) {
timer.invalidate()
let hardness = sender.currentTitle!
secondsRemaining = eggTimes[hardness]!
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector:
#selector(updateTimer), userInfo: nil, repeats: true)
func updateTimer() {
if secondsRemaining > 0 {
print("\(secondsRemaining) seconds left to finish")
secondsRemaining -= 1
}
else {
timer.invalidate()
progress.text = "DONE"
}
}
}
}
The issue you're having is that the func updateTimer is declared under the #selector and as such isn't "available yet" to put it simply. What you probably wanted is to move the function outside the hardnessSelected as such:
class ViewController: UIViewController {
#IBOutlet weak var progress: UILabel!
let eggTimes = ["Soft" :3, "Medium":4, "Hard":6]
var secondsRemaining = 60
var timer = Timer()
#IBAction func hardnessSelected(_ sender: UIButton) {
self.timer.invalidate()
let hardness = sender.currentTitle!
self.secondsRemaining = self.eggTimes[hardness]!
self.timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(self.updateTimer), userInfo: nil, repeats: true)
}
#objc func updateTimer() {
if self.secondsRemaining > 0 {
print("\(self.secondsRemaining) seconds left to finish")
self.secondsRemaining -= 1
}
else {
self.timer.invalidate()
self.progress.text = "DONE"
}
}
}
You also need to add #objc in front of the function name to expose it to ObjC runtime. You can read more about that here.

How to update the NSProgressIndicator?

I have problem with NSProgress. The problem is that NSProgressIndicator is not updating during the process and showing only a small completed portion at the end of process. The localizedDescription is also showing only at the end of the process, but as 100% completed.
So, I have a class with one method findRepeatsWithProgressReporting using NSProgress
class TestProgress: NSObject, ProgressReporting
{
let progress: Progress
override init()
{
progress = Progress()
super.init()
}
func findRepeatsWithProgressReporting(stringToSearch: String, minimalLength: Int, maximalLength: Int) -> [String]
{
var arrayOfRepeats = [String]()
progress.totalUnitCount = Int64((minimalLength...maximalLength).count)
for i in minimalLength...maximalLength
{
let arrayOfStrings = stringToSearch.chopString(stringOut: stringToSearch, length: i)
let arrayOfUniqueStrings = Array(Set(arrayOfStrings))
for each in arrayOfUniqueStrings
{
let arrayOfNSRanges = stringToSearch.searchForNSRangesOfStringInString(stringOut: stringToSearch, stringIn: each)
var positions = String()
if arrayOfNSRanges.count > 1
{
for each1 in arrayOfNSRanges
{
let repeatStart = String(each1.location + 1)
let repeatEnd = String(each1.location + each1.length)
positions += "(" + repeatStart + "-" + repeatEnd + ")"
}
let stringToShow = each + " " + positions
arrayOfRepeats.append(stringToShow)
}
}
progress.completedUnitCount += 1
}
return arrayOfRepeats
}
}
Then, in myVewContrloler I have parentProgress repeatsProgress having totalUnitCount: 10 and have added the task of the method findRepeatsWithProgressReporting as childProgress to the parentProgress repeatsProgress using repeatsProgress.becomeCurrent(withPendingUnitCount: 10).
private var progressObservationContext = 0
class myVewContrloler: NSViewController
{
...
var testProgress = TestProgress ()
var repeatsProgress = Progress()
#IBOutlet weak var repeatsSearchProgressBar: NSProgressIndicator!
#IBOutlet weak var repeatsPercentText: NSTextField!
#IBOutlet weak var minimalLength: NSTextField!
#IBOutlet weak var maximalLength: NSTextField!
#IBOutlet var foundRepeats: NSTextView!
#IBAction func actionFindRepeats(_ sender: AnyObject)
{
repeatsProgress = Progress(totalUnitCount: 10)
let options : NSKeyValueObservingOptions = [.new, .old, .initial, .prior]
repeatsProgress.addObserver(self, forKeyPath: "fractionCompleted", options: options, context: &progressObservationContext)
repeatsProgress.addObserver(self, forKeyPath: "localizedDescription", options: options, context: &progressObservationContext)
var arrayOfRepeats = [String]()
repeatsProgress.becomeCurrent(withPendingUnitCount: 10)
arrayOfRepeats = testProgress.findRepeatsWithProgressReporting(stringToSearch: stringToSearch, minimalLength: minimalLength.integerValue, maximalLength: maximalLength.integerValue)
...
repeatsProgress.removeObserver(self, forKeyPath: "fractionCompleted")
repeatsProgress.removeObserver(self, forKeyPath: "localizedDescription")
repeatsProgress.resignCurrent()
}
}
The last part is for KVO :
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?)
{
guard context == &progressObservationContext else {
super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
return
}
if keyPath == "fractionCompleted"
{
OperationQueue.main.addOperation{
let progress = object as! Progress
self.repeatsSearchProgressBar.doubleValue = progress.fractionCompleted
self.repeatsPercentText.stringValue = progress.localizedDescription
}
}
}
I have added
print("Observed Something")
inside of the
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?)
{ ...
and what I see is two times printing the "Observed Something"immediately after start and six times at the end, no printing in between (as it expected to be for the updating process). What can be the reason ?
This seems like a concurrency problem. Since func actionFindRepeats(_ sender: AnyObject) is running in the main thread, it's concurring with the UI updates, which affects the NSProgressIndicator directly.
See the last example of that answer for more details about that:
https://stackoverflow.com/a/35810608/4370893
You can try adding all the content of your actionFindRepeats function into that block and see if it works:
DispatchQueue.global().async {
// qos' default value is ´DispatchQoS.QoSClass.default`
}
Reference for that block:
https://stackoverflow.com/a/37806522/4370893

swift Detect the correct textfield to add an attribute

i´m writing an input text quiz app, and i have an array of Int where i can store if answer was correct or not with 0 or 1 and also i have 3 textfields where i write the answers, and i want to change the textfields back ground color to red or green depending on the answers variable ,, if index variable its 1 change color to green and if is 0 change color to red.. this is what i have
#IBOutlet var textField1: UITextField!
#IBOutlet var textField2: UITextField!
#IBOutlet var textField3: UITextField!
//change int to 1 if answer was correct (3, ea for each textfield)
var answers = [0,0,0]
#IBAction func button(sender: AnyObject) {
for (index, answer) in goodAnswers.enumerate() {
print (answer)
if answer != 0 {
print ("ok")
} else {
print("not ok")
}
}
}
thanks !
You need something like this:
var goodAnswers = ["One", "Two", "Three"]
var textFields:[Int:UITextField]!
override func viewDidLoad() {
super.viewDidLoad()
self.textFields = [0:textField, 1:textField2]
}
#IBAction func btnClick(sender: AnyObject) {
for(index, answer) in goodAnswers.enumerate() {
if textFields[index]?.text == answer {
textFields[index]?.backgroundColor = UIColor.greenColor()
}
else {
textFields[index]?.backgroundColor = UIColor.redColor()
}
}
}
UPDATE:
If you want to have another good answers simply change your code to like this:
Declare new property:
var collectionOfGoodAnswers: [Int : [String]]!
and in viewDidLoad() method:
self.collectionOfGoodAnswers = [0: ["Hello", "World"],
1: ["Welcome", "Friend"]]
and then implement the click action:
#IBAction func btnClick(sender: AnyObject) {
for(index, _) in collectionOfGoodAnswers.enumerate() {
guard let goodAnswer = collectionOfGoodAnswers[index] else { return }
guard let answer = textFields[index] else { return }
guard let text = answer.text else { return }
if goodAnswer.contains(text) {
textFields[index]?.backgroundColor = UIColor.greenColor()
}
else {
textFields[index]?.backgroundColor = UIColor.redColor()
}
}
}
hope it helps.

swift array read/write data to file

I'd like to read data from an array and write data to a file and viceversa. The file itself has a known path.
The BTTableCell class manages and populates the tableView.
I'm using dati_Riga class in order to have a single array. I thought it would be easier to read and save data using WriteToFile in order to write data and NSMutableArray to read them, but I'm having trouble.
In the following code snippet of the ViewController file you can see functions I wrote in order to open and save data which don't work.
Where did I get wrong? My idea is to save data using BTTableCell but I wasn't able to make it work.
Data structure:
import Cocoa
class BPTableCell:NSTableCellView {
#IBOutlet weak var item_IconaFile: NSImageView!
#IBOutlet weak var item_NomeFile: NSTextField!
#IBOutlet weak var item_PathFile: NSTextField!
#IBOutlet weak var item_MD5: NSTextField!
#IBOutlet weak var item_SHA1: NSTextField!
}
class dati_Riga {
var dati_Riga_item_IconaFile: NSImage!
var dati_Riga_item_NomeFile: String!
var dati_Riga_item_PathFile: String!
var dati_Riga_item_MD5: String!
var dati_Riga_item_SHA1: String!
init (dati_Riga_item_IconaFile: NSImage, dati_Riga_item_NomeFile: String, dati_Riga_item_PathFile: String, dati_Riga_item_MD5: String, dati_Riga_item_SHA1: String)
{
self.dati_Riga_item_IconaFile = dati_Riga_item_IconaFile
self.dati_Riga_item_NomeFile = dati_Riga_item_NomeFile
self.dati_Riga_item_PathFile = dati_Riga_item_PathFile
self.dati_Riga_item_MD5 = dati_Riga_item_MD5
self.dati_Riga_item_SHA1 = dati_Riga_item_SHA1
}
}
Extract from "ViewController.swift":
import Cocoa
import Foundation
import AppKit
import CryptoSwift
class ViewController: NSViewController, NSTableViewDataSource, NSTableViewDelegate {
#IBOutlet weak var tableview: NSTableView!
var item_IconaFile = [NSImage]()
var item_NomeFile = [String]()
var item_PathFile = [String]()
var item_MD5 = [String]()
var item_SHA1 = [String]()
var miei_Dati_Riga : [dati_Riga] = [dati_Riga(dati_Riga_item_IconaFile: NSImage(), dati_Riga_item_NomeFile: "", dati_Riga_item_PathFile: "", dati_Riga_item_MD5: "", dati_Riga_item_SHA1: "")]
override func viewDidLoad() {
super.viewDidLoad()
self.miei_Dati_Riga.removeAtIndex(0)
}
override var representedObject: AnyObject? {
didSet {
// Update the view, if already loaded.
}
}
// MARK: Funzioni relative la TableView
func tableView(tableView: NSTableView, viewForTableColumn tableColumn: NSTableColumn?, row: Int) -> NSView? {
let result : BPTableCell = tableView.makeViewWithIdentifier(tableColumn!.identifier, owner: self) as! BPTableCell
result.item_IconaFile.image = item_IconaFile[row]
result.item_NomeFile.stringValue = item_NomeFile[row]
result.item_PathFile.stringValue = item_PathFile[row]
result.item_MD5.stringValue = item_MD5[row]
result.item_SHA1.stringValue = item_SHA1[row]
return result
}
func numberOfRowsInTableView(tableView: NSTableView) -> Int {
let num_Righe = item_NomeFile.count
return num_Righe
}
// MARK: Apri e Salva file
#IBAction func Save_File(sender: NSMenuItem) {
let salva_File = NSSavePanel()
salva_File.extensionHidden = true
salva_File.canSelectHiddenExtension = true
salva_File.allowedFileTypes = ["cpa"]
salva_File.beginWithCompletionHandler { (result:Int) -> Void in
if result == NSFileHandlingPanelOKButton {
let save_URL_File = salva_File.URL
let mio_Array: NSArray = self.miei_Dati_Riga
print(self.miei_Dati_Riga.count)
print(self.miei_Dati_Riga[0])
if mio_Array.writeToFile((save_URL_File?.path)!, atomically: true) {
print("File Salvato")}
else {
print("File Non Salvato")
}
}
}
}
#IBAction func Open_File(sender: NSMenuItem) {
let apri_File = NSOpenPanel()
apri_File.allowedFileTypes = ["cpa"]
apri_File.beginWithCompletionHandler { (result:Int) -> Void in
if result == NSFileHandlingPanelOKButton {
let contenuto_File = NSMutableArray (contentsOfURL: apri_File.URL!)
self.tableview.reloadData()
}
}
}

Sigabrt swift Xcode (making a timer)

I'm trying to make a stopwatch, and I can't seem to understand why I am getting a sigabrt with my application. Sorry I didn't know what to include, so I included everything.
var timer = NSTimer()
var minutes: Int = 0
var seconds: Int = 0
var fractions: Int = 0
var startStopWatch: Bool = true
var StopwatchString: String = ""
#IBOutlet weak var display: UILabel!
#IBAction func start(sender: UIButton) {
if startStopWatch == true {
NSTimer.scheduledTimerWithTimeInterval(0.01, target: self, selector: Selector("updateStopwatch"), userInfo: nil, repeats: true)
startStopWatch = false
} else {
timer.invalidate()
startStopWatch = true
}
}
#IBAction func reset(sender: UIButton) {
}
override func viewDidLoad() {
super.viewDidLoad()
display.text = "00:00.00"
}
func updateStopWatch() {
fractions += 1
if fractions == 100 {
seconds += 1
fractions = 0
}
if seconds == 60 {
minutes += 1
seconds = 0
}
let fractionsString = fractions > 9 ? "\(fractions)" : "0\(fractions)"
let secondsString = seconds > 9 ? "\(seconds)" : "0\(seconds)"
let minutesString = minutes > 9 ? "\(minutes)" : "0\(minutes)"
StopwatchString = "\(minutesString):\(secondsString).\(fractionsString)"
display.text = StopwatchString
}
I cut and pasted your code into a project and when I tapped the start button the first line of the error message said:
-[My.ViewController updateStopwatch]: unrecognized selector sent to instance 0x7fe0034b3520
That tells you all you need to know. You send the updateStopwatch message to your view controller but it doesn't implement that method. I noticed though that your ViewController does implement an updateStopWatch method. Looks like a basic capitalization error to me.
Always, always, always, read at least the first line of the error message.
Here are some fixes:
+I changed the timer variable initially to nil - it will be saved in the start function.
+Your if statement in the start function looked like this:
if startStopWatch == true
But it should be like this:
if (startStopWatch)
Hope this helpes :)
var timer = nil
var minutes = 0
var seconds = 0
var fractions = 0
var startStopWatch = true
var StopwatchString = ""
#IBOutlet weak var display: UILabel!
#IBAction func start(sender: UIButton) {
if (startStopWatch == true) {
timer = NSTimer.scheduledTimerWithTimeInterval(0.01, target: self, selector: Selector("updateStopwatch"), userInfo: nil, repeats: true)
startStopWatch = false
//I added one thing. If the start button is pushed the text will change to stop. You can change this if you like.
sender.setTitle("Stop", forState: .Normal)
//
} else {
timer.invalidate()
startStopWatch = true
}
}
#IBAction func reset(sender: UIButton) {
display.text! = "00:00.00"
}
override func viewDidLoad() {
super.viewDidLoad()
display.text! = "00:00.00"
}
func updateStopWatch() {
fractions++
if (fractions == 100) {
seconds++
fractions = 0
}
if (seconds == 60) {
minutes++
seconds = 0
}
var fractionsString = fractions > 9 ? "\(fractions)" : "0\(fractions)"
var secondsString = seconds > 9 ? "\(seconds)" : "0\(seconds)"
var minutesString = minutes > 9 ? "\(minutes)" : "0\(minutes)"
StopwatchString = "\(minutesString):\(secondsString).\(fractionsString)"
display.text! = StopwatchString
}

Resources