How to use same value for updated variables until they take new value (Swift) - swift

If i print the value of "self.q" . My programs prints the same value 10-12 times as it keeps getting updated. I want to print the value just once until the updated value is a new one. I am new to swift, not sure how to go about it.
some func{
if (type == "q") {
let json = JSON(receivedAsJSON)
let receivedQ = json["q"].stringValue
self.q = receivedQ
self.updateLabels()
print(self.q)
}
//function to update value received
func updateLabels() {
qLabel.stringValue = self.q
}

I've renamed some variables just for clarity in this example. You could try something like this:
func someFunction() {
let json = JSON(receivedAsJSON)
let newValue = json["q"].stringValue
updateLabels(newValue)
// if the two values are different, then print the new value
if (newValue != oldValue) {
print("New value: \(newValue)")
// update the oldValue so we can do the comparison next time.
oldValue = newValue
}
}

Related

Coredata/swift : hasChanges not as expected

This function is not acting as expected. I'm trying to nil a set of fields.The earlier section gets the correct field names, and is used in other functions. I've got about ten tables, and they all share the same context, in case that matters.
The first unexpected thing is that "yes, changes" never runs, so I presume that the settings object is detached from its context. Or perhaps CoreData treats nil as some kind of exception to triggering the .hasChanges flag?
When it runs, the save throws no errors, and the object displays as expected, displayed with the values set to nil. But there are no changes in the db.
I can save data into these fields without problem, and confirm that in the db; this problem only happens with setting the value to nil.
static func clearSettings(_ s : Set<PaletteElementType>? = nil) {
guard var setting = activeSetting() else {return}
print(setting.id)
let cats = s ?? PaletteView.compCatButtons
let tgts = setting.getAssociatedFieldNames(tgts: cats, clearing : true, values: false)
for (key, val) in tgts {
var src = Set((val as? Dictionary<FieldNameSuffixes, String>)!.values)
if key == .catBgndButton {
src = src.union(["opacity", "opacityStart", "opacityStartDelta","opacityEnd", "opacityEndDelta", "opacityTimer"])
}
for s in src {
print(s)
setting.setNilValueForKey(s)
if Blocks.context!.hasChanges {
print("yes, changes")
}
do {
try Blocks.context!.save()
print("deleted \(setting.value(forKey: s))")
} catch { print("deadly dogs")}
}
print("val is \(setting)")
}
}
OK, working when I do it this way:
static func clearSettings(_ s : Set<PaletteElementType>? = nil) {
guard var setting = activeSetting() else {return}
print(setting.id)
let cats = s ?? PaletteView.compCatButtons
let tgts = setting.getAssociatedFieldNames(tgts: cats, clearing : true, values: false)
for (key, val) in tgts {
var src = Set((val as? Dictionary<FieldNameSuffixes, String>)!.values)
if key == .catBgndButton {
src = src.union(["opacity", "opacityStart", "opacityStartDelta","opacityEnd", "opacityEndDelta", "opacityTimer"])
}
for n in setting.entity.attributesByName.enumerated() {
if src.contains( n.element.key as String) {
print("found one")
setting.setNilValueForKey(n.element.key)
}
}
do {
try Blocks.context!.save()
} catch {print("bumpy beasts")}
print("val is \(setting)")
}
}
Happy it's working, but I don't really understand the distinction here. What is the better way to handle this? I'm not chasing some super performant code, so I don't mind a few extra loops... but what's the deal?

How to remove a variable from the field of view

while true {
print ( """
1. Log in
2. Create new user
3. Quit
""")
if let numberString = readLine(), let number = Int(numberString) {
print("you entered \(number)")
break
} else {
print("Try again")
}
}
It is necessary to use the number variable in the future to compare it.
How can it be taken out of sight?
When I try to make a global var something goes wrong:
var numberString: String?
var number: Int?
while true {
print ( """
1. Log in
2. Create new user
3. Quit
""")
if numberString = readLine(), number = Int(numberString) {
print("you entered \(number)")
break
} else {
print("Try again")
}
}
Considering that you are creating a command prompt and that choice has no meaning outside your loop there is no need to make it global. You only need to switch the user selection and decide what to do from there. Note that if you try to break from inside the switch you won't exit your loop as I showed to you in your last question. To allow the compiler to know that you want to break the while loop instead of the switch you need to label your while loop statement, this way you can specify what you want to break when you have a switch inside a loop. Try like this:
func getValue() -> Int? {
guard let line = readLine(), let value = Int(line) else {
return nil
}
return value
}
question: while true {
print("""
1. Log in
2. Create new user
3. Quit
""")
guard let value = getValue() else {
continue
}
switch value {
case 1:
print("you have selected number one")
case 2:
print("you have selected number two")
case 3:
print("Good bye")
break question
default:
print("Try again")
}
}
There is not much information to go off of here, but I think I can help. In the first script, you are creating a new variable and setting the value for that variable:
if let numberString = readLine(), let number = Int(numberString) { ... }
In your second script, you have to global variables, but at no point have you provided them a value. What you need to do is provide both global variables (numberString and number) a value before comparing them. As such, you need to use the == sign to compare different variables/ types. For instance:
var numberString: String?
var number: Int?
while true {
print("""
1. Log in
2. Create new user
3. Quit
""")
numberString = readLine()
number = Int(numberString!)
}
You can now compare and or print your global variables...
Final Code
var numberString: String?
var number: Int?
while true {
print("""
1. Log in
2. Create new user
3. Quit
""")
numberString = readLine()
number = Int(numberString!)
if number == 1 {
print("you have selected number one")
} else if number == 2 {
print("you have selected number two")
} else if number == 3 {
print("you have selected number three")
} else {
print("Try again")
}
}
Due to the fact that both variables numberString and number are now global variables, you can access them in the future if you need to compare them again.

Dictionary in Dictionary value search

I am downloading information from a Firebase database and it is being inputted via a for loop into:
static var Reports = [String:[String:String]]()
I need to figure out a way to search the inside values for a certain string
I have messed around with this but can't seem to get it inside the inside dictionary (If that makes sense)
for values in Reports.count {
if let item = Reports["favorite drink"] {
print(item)
}
}
I need to have a search string then a number of times the value appears like so:
func findString(dict Dictionary) -> Int {
var ReportsLevel1 = 0
(for loop I'm guessing)
search here for string
return ReportsLevel1
}
Tip: the outside dictionary keys are not set in stone, they depend on what time and date the report was submitted
To find out the numberOfTimes in which "yourSearchString" appears you can do as follows
var numberOfTimes = 0
for internalDictionary in reports.values
{
for value in internalDictionary.values
{
if (value == "yourSearchString") { numberOfTimes += 1 }
}
}
or
let numberOfTimes = reports.flatMap { internalDictsArray in internalDictsArray.value.filter { $0.value == "yourSearchString" } }.count

Swift step through dictionary

I was wondering if there's a way to step through a dictionary in Swift. I know I can iterate through, but I was hoping to step one by one through a dictionary of items as the user taps a "next" button.
I was thinking I could initially iterate through the dictionary and store the keys in an array, then step through the keys and retrieve each item as needed, since the array can be indexed. This seems a little inelegant, though. Any thoughts?
My current approach:
var iterator = 0
var keys = [String]()
func loadKeys() {
for (key, value) in items {
keys.append(key)
}
}
func step() {
iterator += 1
let currentKey = keys[iterator]
let currentItem = items[currentKey]
}
I figure it would work just fine, just not sure it's the best practice.
Thanks for your help!
A dictionary also provides you with an iterator, so you can step through it using that:
var iterator = items.makeIterator()
func step() {
if let v = iterator.next() {
let currentKey = v.key
let currentValue = v.value
}
}
A dictionary is an indexed collection, so you can use a dictionary's index to step through the keys and values:
var i = items.startIndex
func step() {
guard i != items.endIndex else {
// at the end of the dictionary
return
}
let (currentKey, currentValue) = items[i]
i = items.index(after: i)
}

databaseReference.observe(DataEventType.value, with:{(DataSnapshot) not working properly all the time

func checkPaid(utilityId : String) -> Int{
var amount:String = ""
var status = 0
print("inside new function ")
print ("\(utilityId) inside new function ")
self.databaseRefPayment.observe(DataEventType.value, with:{(DataSnapshot) in
if DataSnapshot.childrenCount > 0 {
for payments in DataSnapshot.children.allObjects as! [DataSnapshot]{
var paymentsObject = payments.value as? NSDictionary
/*
if(paymentsObject!["month"] as! String == monthCheck && paymentsObject!["year"] as! String == monthCheck && paymentsObject!["utilityid"] as! String == utilityId as! String){ */
if(paymentsObject!["utilityId"] as! String == utilityId){
amount = paymentsObject!["amount"] as! String
print(amount)
print("Ypur program is working perfect")
status = 1
}
}
}
})
return status
}
The above function is filtering the data present in payments node based on the value for utilityId getting passed in the function . But the strange thing is observe(DataEventType.value, with:{(DataSnapshot) this event is not getting triggered all the time . Its just skipping that portion unnecessarily . I am very new to firebase and getting really mad with these kind of unpredicted behaviours . Please help me in this . feel free to ask for any clarifications .
The firebase executes firebase query functions in different thread , so after u call check paid(), it runs the checkpaid() firebase query in another thread,and it will return from the function , eventhough ur query is running in the background..so it will seem like,checkpaid() is not working , but actually it's running on another thread.
I think you first fetch all the required data from payment, and store it in a list , and then use that list to compare with utility.
Every time this function is called it adds/resets the Key-Value Observer for whichever child node you are observing it doesn't actually check the value unless it is changed. I believe it is your intention to call checkPaid(utilityId:) to check the child is 'paid' by some means. There is no need to add a KVO if you are directly reading the value for a single snapshot. consider the following:
func checkPaid(utilityId: String) -> Bool {
//Assume it is not paid if we cannot verify it.
var isPaid = false
//Create a new reference to Firebase Database
var ref: DatabaseReference!
ref = Database.database().reference().child(utilityId)
//Get the values for the child, test if it is paid or not.
ref.queryOrderedByValue().observeSingleEvent(of: .value) { (snapshot) in
if (snapshot.value is NSNull) {
print("No Child With \(utilityId) Exists")
} else {
//child with utilityId exists, in case multiple utilityId's exist with the same value..
for child in snapshot.children.allObjects as! [DataSnapshot] {
if let values = child.value as? [String : AnyObject] {
let uid = child.key //utilityId
var month:String = ""
var year:String = ""
var amount:String = ""
//var amount:Double = 0.0
//get values from parent
if let m = values["month"] as? String {
month = m
}
if let y = values["year"] as? String {
year = y
}
if let a = values["amount"] as? String {
amount = a
}
/*
if let a = values["amount"] as? Double {
amount = a
}
*/
//??
if ((month == monthCheck) && (year == monthCheck)) {
isPaid = true
}
}
}
}
return isPaid
}
I am making one assumption here; that utilityId is the key for the child.
if you have parent nodes to utilityId you'll have to transverse those as well when you reference the database:
ref = Database.database().reference().child(utilities).child(utilityId) ..etc
If you need a KVO to update a local property I suggest adding/calling it in viewDidLoad, it's completion handler should take care of updating whichever properties are updated when they change in Firebase.