I have a simple piece of code that I guess I'm using local and global variables in it. But, I have a hard time understanding what's going wrong in here. I am setting "var hhhh:Int = 0" at first. Then, inside the if statement, I set "hhhh = appleCount["count"] as! Int". Since appleCount["count"] is not zero and has some value, hhhh gets its' value (I tried that uisng a print statement and hhhh is not zero inside if statement), but, later when I print hhhh with print("(hhhh)") outside if, I again get zero for its' value. Does it have something to do with local and global variables? I'm trying to communicate with Parse in the code by the way.
Thanks a lot for your kind help
import UIKit
import Parse
class NewsPageViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad(
var hhhh:Int = 0
var tttt:Int = 0
var cccc:Int = 1
if cccc == 1 {
var query = PFQuery(className: "Count")
query.getObjectInBackgroundWithId("RhC25gVjZm", block: { (object: PFObject?, error: NSError?) -> Void in
if error != nil {
print(error)
} else if let appleCount = object {
appleCount["count"] = appleCount["count"] as! Int + 1
hhhh = appleCount["count"] as! Int
appleCount.saveInBackground()
}
})
}
print(hhhh)
}
}
It does not have to do with local and global variables. It has to do with background threads. The code in brackets {} after the parameter label "block" will run in a background thread at a later time.
Your print(hhhh) is running before the block has had a chance to change hhhh. Move the print statement back inside the block so you can see the variable being set.
osteven response helped me a lot understanding the problem. Thanks a lot man. In addition to osteven's response, I just waned to add that a major part of my problem was coming because I was trying to do some mathematical operations on the objects I was trying to save in Parse. So, I also figured that I could create an array, save my objects inside that array, and then access the key and update the values. Here is a sample code of what I am using right now. It does some mathematical operation on two different objects saved in Parse and updates the label's text on screen. For accessing the two objects in Parse and updating them I'm using an array.
Hope the answers here will help someone in future as the awesome people of StackOverFlow are helping me now.
Peace!
var hhhh : [Int] = []
#IBOutlet weak var jPercent: UILabel!
#IBOutlet weak var yPercent: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
var query = PFQuery(className: "Count")
if cccc == 1 {
query.getObjectInBackgroundWithId("DcU9tdRdnl", block: { (object: PFObject?, error: NSError?) -> Void in
if error != nil {
print(error)
} else if let jCount = object {
jCount["count"] = jCount["count"] as! Int + 1
jCount.saveInBackground()
}
})
} else if cccc == 2 {
query.getObjectInBackgroundWithId("5Bq4HJbFa3", block: { (object: PFObject?, error: NSError?) -> Void in
if error != nil {
print(error)
} else if let yCount = object {
yCount["count"] = yCount["count"] as! Int + 1
yCount.saveInBackground()
}
})
}
//shouldn't use same query for findObjectsInBackgroundWithBlock and getObjectInBackgroundWithId otherwise you'll get a runtime error
var query2 = PFQuery(className: "Count")
query2.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if let users = objects {
for object in users {
if let user = object["count"] as? Int {
self.hhhh.append(user)
}
}
}
var gggg = 100*Float(self.hhhh[0])/(Float(self.hhhh[0]+self.hhhh[1]))
self.yPercent.text = String(format: "%.1f", gggg) + "%"
self.jPercent.text = String(format: "%.1f", 100 - gggg) + "%"
print(self.hhhh[0])
}
}
Related
While writing a UI for Swift that tales user input into and writes the info into arrays, the "getCommand()" function with the "readLine()!" statement returns the error "Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value" I don't know how to fix it with Optional Binding.
import Foundation
struct StatsVC {
var data = [String : Stats]()
var current = ""
func getCommand() -> [String] {
print("Command" , terminator : "...")
return splitStrPar(readLine()!) //the troublemaker
}
mutating func runStats() {
print("Hello, Welcome to the Krantz UI! Please enter your stats: ")
var command = getCommand()
var infoData: [Stats] = []
while(command[0] != "quit") {
switch command[0] {
case "current" : //code not important here, deleted other options for simplicity
default : print("I don't have that command in my system")
}
command = getCommand()
if(command[0] == "quit") {
print("Krantz Laboratories Thanks You For a Productive Session")
}
}
}
}
//statsVC.swift
func splitStrPar(_ expression: String) -> [String]{
return expression.split{$0 == " "}.map{ String($0) }
}
func splitStrLin(_ expression: String) -> [String]{
return expression.split{$0 == "\n"}.map{ String($0) }
}
//stats.swift
import Foundation
struct Stats {
var values: [Double]
init(values: [Double]){
self.values = values
}
//other functions not important here
}
//main.swift
var vc = StatsVC()
vc.runStats()
Change your struct code to the following to properly handle optional wrappers. It is poor practice to use the forced optional wrapper postfix operator !. I also took the liberty of modifying your iteration through the commands array to better accomplish what I think you are trying to do.
struct StatsVC {
var data = [String : Stats]()
var current = ""
func getCommands() -> [String] {
print("Command" , terminator : "...")
guard let line = readLine() else { return [] }
return splitStrPar(line)
}
mutating func runStats() {
print("Hello, Welcome to the Krantz CLI! Please enter your stats: ")
let commands = getCommands()
var infoData: [Stats] = []
for command in commands {
switch command {
case "current" :
break //code not important here, deleted other options for simplicity
case "quit":
print("Krantz Laboratories Thanks You For a Productive Session")
return
default :
print("I don't have that command in my system")
}
}
}
}
I'm trying to make a type of polling code that once a person presses an option, a value in the Firebase database updates by one but that person cannot access it again.
Right now, I'm trying to test only one button. For reference, my database is:
"Redacted for privacy"
-> "MainContent"
->-> "Polls"
->->-> "GunControl"
->->->-> "BackGroundChecks"
->->->->-> OptionA: 0
->->->->-> OptionB: 0
->->->->-> OptionC: 0
->->->->-> OptionD: 0
Unfortunately I do not have enough points to show a picture so please bear with it.
My Code is:
var counterRef = Database.database().reference()
var optionA: Int = 0
var retrieveData: Int = 0
static var pollAnswered: Bool = false
#IBAction func optionA(_ sender: Any) {
print("Called")
self.counterRef = Database.database().reference(fromURL: "URL Redacted For Privacy")
print("Called2")
updateOptionADos()
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func updateOptionADos() {
print("Called3")
counterRef.observeSingleEvent(of: .value, with: { snapshot in
let valString = snapshot.value as? String
if (valString != nil && PollViewController.pollAnswered == false){
var value = Int(valString!)
value = value! + 1
self.retrieveData = value!
self.optionA = value!
print(self.optionA)
self.counterRef.setValue("\(String(describing: value))")
PollViewController.pollAnswered = true
print("Noice")
}
else {
print("ya done f***** up")
}
})
}
It is supposed to call updateOptionADos() to determine what value is in the location I am trying to access (OptionA) and add 1 to it while storing that updated value in the variable optionA for later use in statistics. It builds perfectly, but I keep getting the "ya done f***** up" which tells me that the database value isn't storing for valString. Someone please help me fix this. What have I done wrong? I'm at a loss.
You get the value and try to cast it as a String:
let valString = snapshot.value as? String
And then you cast that string to an Int:
var value = Int(valString!)
If you are storing the count as an Integer, not a string, snapshot.value as? String will return nil, as it is not a String.
My problem is as follows: I have an argument class where all arguments have a parentId which are indeed objectId of other arguments. I would like to write a query where I can get a list of all arguments that are connected to each other with this kind of parent-child relationship. So i have tried this..
class ArgumentViewController: UIViewController {
var all = [String]()
var temporaryId = "vEKV1xCO09"
override func viewDidLoad() {
super.viewDidLoad()
for _ in 1...3 {
let query = PFQuery(className: "Argument").whereKey("objectId", equalTo: temporaryId)
query.findObjectsInBackground { (objects, error) in
if let arguments = objects {
for argument in arguments {
self.all.append(argument["parentId"] as! String)
print(self.all)
self.temporaryId = argument["parentId"] as! String
}
}
}
}
}
but the problem is temporaryId inside the loop does not update itself. It remains the same in all iterartions. Hence when i do print(self.all) i simply get an array of 3 strings which all are parent of my initial argument
My goal is to get an array that is [parent of my initial argument, parent of parent of my initial argument, parent of parent of parent of my ...]
I have searched similar topics but couldn't find a solution. Any help would be very appreciated.
Since query.findObjectsInBackground runs in background thread, there is no way to update temporaryId with the newly retrieved #"parentId" in every for loop.
So I guess you could create a recursive function, something like:
func getParentId() {
let query = PFQuery(className: "Argument").whereKey("objectId", equalTo: temporaryId)
query.findObjectsInBackground { (objects, error) in
if let arguments = objects {
for argument in arguments {
self.all.append(argument["parentId"] as! String)
print(self.all)
self.temporaryId = argument["parentId"] as! String
while (all.count <= 3) {
getParentId()
}
}
}
}
}
I haven't done enough practice in Swift as i'm an Objective-C developer, so I'm sorry if I made some syntax errors.
Here's my doozy.
I've got this lovely little function in a file called functions.swift
//functions.swift
func latestActiveGoal() -> Object {
let realm = try! Realm()
let currentGoal = realm.objects(Goal).filter("Active == 1").sorted("CreatedOn").last
return currentGoal!
}
which returns a Goal object. (A Goal might be wanting to lose weight, or stop being so inept at Swift).
In a different view controller, I want to access this object. Here's what I'm trying:
//viewController.swift
#IBOutlet weak var aimText: UILabel!
let funky = functions()
func getGoals(){
var currentGoal = funky.latestActiveGoal()
print(currentGoal)
aimText.text = currentGoal.Title
}
The print(CurrentGoal) output shows this:
Goal {
id = 276;
Title = Goal Title;
Aim = Aim;
Action = Nothing;
Active = 1;
CreatedOn = 2016-02-12 00:14:45 +0000;
}
aimText.text = currentGoal.Title and aimText = currentGoal.Title both throw the error:
Value of 'Object' has no member 'Title'
By printing the contents of the object, I can see the data, but can't figure out how. Any help greatly appreciated.
As the error message said, currentGoal is a value of Object type which doesn't have member Title.
This is because function latestActiveGoal returns Object instead of Goal. You just need to make it return Goal by change the return type:
func latestActiveGoal() -> Goal {
Just replace your functions with below code.
It will works perfect.
This fuction will check if goal available, then only it will return.
func latestActiveGoal() -> Object? {
let realm = try! Realm()
let currentGoals = realm.objects(Goal).filter("Active == 1").sorted("CreatedOn")
if currentGoals.count > 0 {
return currentGoals.last;
}
return nil;
}
Your getGoals method will be as follow.
func getGoals(){
if let currentGoalObject = funky.latestActiveGoal() {
print(currentGoalObject)
let goal = currentGoalObject as! Goal
print(goal.Title)
aimText.text = goal.Title
}
}
class ViewController: UIViewController {
#IBOutlet weak var inputField: UITextField!
#IBOutlet weak var output: UITextView!
var guesses : UInt = 0
var number : UInt32 = 0
var gameOver = false
let MAX_GUESSES : UInt = 8
#IBAction func guess(sender: UIButton) {
var possibleGuess : Int? = inputField.text.toInt()
if let guess = possibleGuess {
// possibleGuess exists!
} else {
consoleOut("Please input a valid number!\n")
clearInput()
}
if UInt32(guess) > Int(number) {
consoleOut("\(guess): You guessed too high!\n")
++guesses
} else if UInt32(guess) < number {
consoleOut("\(guess): You guessed too low!\n")
++guesses
} else {
consoleOut("\n\(guess): You win!\n")
consoleOut("Go again? (Y)")
guesses = 0
gameOver = true
}
clearInput()
if (guesses == MAX_GUESSES) {
consoleOut("\nYou lose :(\n")
consoleOut("Go again? (Y)")
guesses = 0
gameOver = true
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
number = generateNewNumber()
consoleOut("Gondolkodom egy számot...\n")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func consoleOut(text : String) {
output.text = output.text + text
}
func generateNewNumber () -> UInt32 {
return arc4random_uniform(100)
}
func clearInput() {
inputField.text = ""
}
}
This is the code that I use and I get the error message at if UInt32(guess) > Int(number) {. I really can't get through this.
(swift) Error: can not invoke '>' with an argument list of type '(UInt32, #lvalue UInt32)'
* This is not exactly your problem, but it may show you a way to get around it :) *
This must be a Swift bug like many others ObjectiveC had.
I'm having the same problem trying to compare an arc4random() number (which is an UInt32 type) with a UInt32() casted string, and I get the same error, which is more outrageous in my case because the two numbers ARE the same type. Which leads me to think that the casting must not be producing the desired result.
I though of creating an auxiliary UIint32 variable and assign it UInt32(theString), butSwift doesn't let you convert a String into UInt32 when defining a variable, so I had to create an auxiliary variable to be converted to Int, and then convert the Int to UInt32 to be able to compare the two numbers:
var theString = "5"
var randomNumber = arc4random() % 10
var UInt32Number = UInt32(theString)
// => ERROR: "Cannot invoke 'init' with an argument of type '#lvalue String!'
// (this is where I realized the comparison line could be suffering from the same problem)
if randomNumber == UInt32(theString) { ... }
// No error here 'cos Swift is supposed to have casted theString into a UInt32
// ...but surprisingly it prompts an ERROR saying it can't compare a UInt32 with a UInt32 (WTF!)
// And here's where I go crazy, because watch what happens in the next lines:
var intValue = theString.toInt()
var UInt32Value = UInt32(intValue!)
if randomNumber == UInt32Value { ... } // => NOW IT WORKS!!
CONCLUSION: Swift is not making the conversion type in the comparison even if it's supposed to. Sometimes it seems to f*** up. Using auxiliary variables with set types can get around the problem.