getting win - loss counter to save in user default swift - ios

I am comparing whether a user should get a win or loss in their score column. I can't get the code to store the win/loss and then add 1 on top of it every time the if statement runs. Here is my if statement, followed by where i call it in the view did load. Cant seem to figure where I'm going wrong. thanks for the help!
viewDidLoad {
let dailyWinsDefault = UserDefaults.standard.integer(forKey: "dailyWinsDefault")
winsLabel.text = "\(dailyWinsDefault)"
print(dailyWinsDefault)
let dailyLossDefault = UserDefaults.standard.integer(forKey: "dailyLossDefault")
lossLabel.text = "\(dailyLossDefault)"
print(dailyLossDefault)
}
showWinLossVC.callbackForWinLoss = { result in
if result > 0.0 {
self.dailyWins += 1
UserDefaults.standard.set(self.dailyWins, forKey: "dailyWinsDefault")
self.winsLabel.text = String(self.dailyWins)
print(self.dailyWins)
}
else if result < 0.0 {
self.dailyLosses += 1
UserDefaults.standard.set(self.dailyLosses, forKey: "dailyLossDefault")
self.lossLabel.text = "\(self.dailyLosses)"

Couple of mistakes
Mistake 1:
Seems like you are setting integer in UserDefault for key dailyWinsDefault using statement
UserDefaults.standard.set(self.dailyWins, forKey: "dailyWinsDefault")
And you expect it to return you String when you retrieve it with
if let dailyWinsDefault = UserDefaults.standard.string(forKey: dailyWinsDefault)
Why will it not return nil ?
use
let dailyWinsDefault = UserDefaults.standard.integer(forKey: "dailyWinsDefault")
Mistake 2:
In your statement
if let dailyWinsDefault = UserDefaults.standard.string(forKey: dailyWinsDefault)
dont you think dailyWinsDefault should be in double quote as its a key and supposed to be string ?
try
let dailyWinsDefault = UserDefaults.standard.integer(forKey: "dailyWinsDefault")
EDIT:
As OP has updated code and now facing a issue with his updated code and requested for help updating my answer.
Couple of issues again
Mistake 1:
In entire ViewDidLoad method u never assigned the value retried from user defaults to property dailyWins and dailyLoses
viewDidLoad {
let dailyWinsDefault = UserDefaults.standard.integer(forKey: "dailyWinsDefault")
self.dailyWins = dailyWinsDefault //this is missing
winsLabel.text = "(dailyWinsDefault)"
print(dailyWinsDefault)
let dailyLossDefault = UserDefaults.standard.integer(forKey: "dailyLossDefault")
self.dailyLosses = dailyLossDefault //this is missing
lossLabel.text = "\(dailyLossDefault)"
print(dailyLossDefault)
}
Mistake 2:
Though not specific to your problem, you should always call super.viewDidLoad in your viewDidLoad unless u have a very firm reason for not doing so
That should help :)

Related

Adding up entered value with an existing value in swift

I have a text field where I can enter a double and it will be displayed on a label in the 2nd view controller. This value will be saved using UserDefaults. I am struggling to find what to do, to be able to then use this saved value and increase it with a new value entered in the text field.
i.e 1st time I enter 5; label displays 5. 2nd time I enter 3; label displays 8.
I tried to use the below if function, but this has not worked. When I enter a value for the 2nd time the label value goes back to 0, if then enter a value again, label is updated with the value entered.
func saveOne() {
UserDefaults.standard.set(weekOneTotal, forKey: "WEEKONE")
secondScreen.weekOneText = String(UserDefaults().double(forKey: "WEEKONE"))
}
func addCorrectSpend () {
guard let addAmount = convertAmount(input: enterField.text!) else {
print("Invalid amount")
return
}
if UserDefaults().double(forKey: "WEEKONE") == 0 {
weekOneTotal += addAmount
secondScreen.weekOneText = String(UserDefaults().double(forKey: "WEEKONE"))
saveOne()
}
else if UserDefaults().double(forKey: "WEEKONE") > 0 {
let defaultOne = UserDefaults.standard
defaultOne.set(defaultOne.double(forKey: "WEEKONE")+addAmount, forKey: "WEEKONE")
secondScreen.weekOneText = String(UserDefaults().double(forKey: "WEEKONE"))
saveOne()
}
}
To answer (quickly) why this is happening: You are setting the initial value in UserDetails.standard, which is correct, but then you are updating the value in a new UserDefaults() object each time.
You can also pare down your code a little bit as there is some unnecessary stuff in there. Ultimately you just need to add the new value to the existing value, so you don't really need to check if the existing value == 0. Here is an example of how I may refactor the above code:
func addCorrectSpend() {
guard let addAmount = convertAmount(input: enterField.text!) else {
print("Invalid amount")
return
}
//Get the existing total (will be 0 if none)
let weekOneAmount = UserDefaults.standard.double(forKey: "WEEKONE")
//Add the existing total to the new amount from your textField
let weekOneTotal = weekOneAmount + addAmount
//Update UserDefaults.standard to the new value
UserDefaults.standard.set(weekOneTotal, forKey: "WEEKONE")
//Set the text
secondScreen.weekOneText = "\(weekOneTotal)"
}
A different approach would be to utilize custom getter & setter for weekOneAmount, so that you can abstract away most of your calls and work with it as a normal variable.
var weekOneAmount: Double {
get {
return UserDefaults.standard.double(forKey: "WEEKONE")
}
set {
UserDefaults.standard.set(newValue, forKey: "WEEKONE")
}
}
Now, whenever you need to read or write, it behaves just like any other variable.

Couchbase lite, Search query taking very long time

When I try to search the couchbase documents of size around 10K, the searching is taking very long time. Below are the code snippet. Can anyone optimize it or suggest me any alternative approach. Thank you.
1) Search function
func search(keyword:String) -> [[String:AnyObject]] {
var results:[[String:AnyObject]]=[]
let searchView = database.viewNamed(AppConstants().SEARCH)
if searchView.mapBlock == nil {
startIndexing()
}
let query = searchView.createQuery()
var docIds = Set<String>()
let result = try query.run()
while let row = result.nextRow() {
let key = "\(row.key)"
let keyArr = keyword.characters.split(" ")
for (index, element) in keyArr.enumerate() {
let keyItem = String(element)
if key.lowercaseString.containsString(keyItem.lowercaseString) {
let value = row.value as! [String:AnyObject]
let id = value["_id"] as? String
if id != nil && !docIds.contains(id!) {
results.append(value)
docIds.insert(id!)
}
}
}
}
}
2) Indexing
func startIndexing() {
let searchView = database.viewNamed(AppConstants().SEARCH)
if searchView.mapBlock == nil {
searchView.setMapBlock({ (doc, emit) in
let docType = doc[AppConstants().DOC_TYPE] as! String
if AppConstants().DOC_TYPE_CONTACT.isEqual(docType) {
self.parseJsonToKeyValues(doc)
for value in self.fields.values {
emit(value, doc)
}
self.fields.removeAll()
}
}, version: "1")
}
}
self.parseJsonToKeyValues(doc) will return me the key value store of my documents to index.
You're emitting the entire document along with every field for your view. This could easily cause your queries to be slow. It also seems unlikely you want to do this, unless you really need to be able to query against every field in your document.
It's considered best practice to set your map function right after opening the database. Waiting until right before you query may or may not slow you down.
See https://developer.couchbase.com/documentation/mobile/current/guides/couchbase-lite/native-api/view/index.html for more, especially the section labeled "Development Considerations".

how to make retrieve button for previous Value

can someone help me
i make button to retrieve previous Values
but i have two TextFiled
i must write in two TextFiled for work retrieve button
i do not want this happens
i want when I write in the first TextFiled, retrieve button work without any problem
but if i write in first TextFiled and second TextFiled at the same time i want retrieve button work without any problem
var previousValues: [String] = [String]();
var previousValues1: [String] = [String]();
previousValues.append(TextFailde.text ?? "error");
previousValues1.append(TextFilde1.text ?? "error");
if self.previousValues.count > 0 {
let previousValue = self.previousValues.removeLast()
let subtracted = (Int(self.lblZeroUs.text!)!) - (Int(previousValue)!)
self.lblZeroUs.text = "\(subtracted)"
}
else if self.previousValues1.count > 0 {
let previousValue = self.previousValues1.removeLast()
let subtracted2 = (Int(self.lblZeroThey.text!)!) - (Int(previousValue)!)
self.lblZeroThey.text = "\(subtracted2)"
}
and here the error
There are many errors, first of all you dont declare your properties with the first letter in uppercase, it's considered a bad practice.
Then, when you involve your properties in mathematical operations what do you need is to assign them a start value, especially if your code try to convert strings.
In Swift, you don’t need to write semicolons at the end of every statement.
I dont know the rest of your code, but your lines crash because you attempt to run mathematical operations using properties have nil as value.
This below it's just an example to avoid the first crashing for nil:
textFailde.text = "0"
textFilde1.text = "0"
previousValues.append(textFailde.text ?? String(0))
previousValues1.append(textFilde1.text ?? String(0))
self.lblZeroUs.text = String(0)
self.lblZeroThey.text = String(0)
if self.previousValues.count > 0 {
let subtracted = (Int(self.lblZeroUs.text!)!) - (Int(self.previousValues.last!))!
self.previousValues.removeLast()
self.lblZeroUs.text = "\(subtracted)"
}
else if self.previousValues1.count > 0 {
let subtracted2 = (Int(self.lblZeroThey.text!)!) - (Int(self.previousValues1.last!))!
self.previousValues1.removeLast()
self.lblZeroThey.text = "\(subtracted2)"
}
previousValues.append(TextFailde.text ?? "error");
previousValues.append(TextFilde1.text ?? "error");
You added to the same array twice, try changing the code to
previousValues.append(TextFailde.text ?? "error");
previousValues1.append(TextFilde1.text ?? "error");

what is effective approach to set default values using NSUserDefaults.standardUserDefaults().registerDefaults(Dictionary<String, AnyObject>)?

I have 4 user settings in the app which are independent of each other. I want to check value for each setting using appropriate method of NSUserDefaults.standardUserDefaults() for each key and if any of the key is not found in user defaults then register the default predefined value.
I do not want to call NSUserDefaults.standardUserDefaults.registerDefaults(Dictionary<String, AnyObject>) every time with app launch , so i am not registering defaults using this method in AppDelegate.Swift- didFinishLaunchingWithOptions with every app launch but i call a method in root view controller's viewDidLoad() which runs a custom logic to check each user settings. if all 4 settings already saved by user no call toregisterDefaults() at all and if any one of settings not saved, call registerDefaults().
Can anyone suggest is there any effective way of doing this or comment on the way i am trying to achieve it ? Will Apple review team approve my logic?
I want to get rid of too many IF's. Below is the logic i have written :-
let userDefaults = NSUserDefaults.standardUserDefaults() as NSUserDefaults
rate = AVSpeechUtteranceDefaultSpeechRate
speech = true
language = AVSpeechSynthesisVoice.currentLanguageCode()
defaultLanguageName = NSLocale.currentLocale().displayNameForKey(NSLocaleIdentifier, value: language)
bttnEffect = "Pop"
var defaultSpeechSettings: Dictionary<String, AnyObject> = ["speechRate": rate, "speech": speech, "languageCode": language, "defLanguageLabel": defaultLanguageName, "gender": bttnEffect ]
var isSpeechRateSettingLoaded = false
var isSpeechSettingLoaded = false
var isLangSettingLoaded = false
var isBttnEffectSettingLoaded = false
if let theRate: Float = userDefaults.valueForKey("speechRate") as? Float {
rate = theRate
defaultSpeechSettings.removeValueForKey("speechRate")
isSpeechRateSettingLoaded = true
}
if let toggleVal: Bool = userDefaults.valueForKey("speech") as? Bool {
speech = toggleVal
defaultSpeechSettings.removeValueForKey("speech")
isSpeechSettingLoaded = true
}
if let langCode = userDefaults.stringForKey("languageCode") {
language = langCode
defaultSpeechSettings.removeValueForKey("languageCode")
defaultSpeechSettings.removeValueForKey("defLanguageLabel")
isLangSettingLoaded = true
}
if let effectStyle = userDefaults.stringForKey("bttnEffect") {
bttnEffect = effectStyle
defaultSpeechSettings.removeValueForKey("bttnEffect")
isBttnEffectSettingLoaded = true
}
if !(isSpeechRateSettingLoaded && isSpeechSettingLoaded && isLangSettingLoaded && isBttnEffectSettingLoaded) {
NSUserDefaults.standardUserDefaults().registerDefaults(defaultSpeechSettings)
}
Apple's review team doesn't care if you write sloppy code.
Note Ken's comment about how registerDefaults() only affects return values if no value is set for the given key.
Aside from that, however, extensions are a nice way to tame NSUserDefaults.
extension NSUserDefaults {
private static let speechRateKey = "speechRate"
var speechRate: Float {
get {
return valueForKey(NSUserDefaults.speechRateKey) as? Float ?? AVSpeechUtteranceDefaultSpeechRate
}
set {
setObject(newValue, forKey: NSUserDefaults.speechRateKey)
synchronize()
}
}
}
// somewhere else:
let speechRate = NSUserDefaults.standardUserDefaults().speechRate
doSomethingWith(speechRate)
NSUserDefaults.standardUserDefaults().speechRate = getNewSpeechRate()

NSObject does not have a member named startIndex

#IBAction func logEmButn(sender: AnyObject) {
let clonCountrLableItem = clonCountLable.text!
let baclCounterLableItem = baclCountLable.text!
let ironCountLableItem = ironCountLable.text!
let gymCountLableItem = gymCountLable.text!
let asp2CountLableItem = asp2CountLable.text!
let fiveHtpLableItem = fiveHtpLable.text!
let selectedLables = [clonCountLable, baclCountLable, ironCountLable, gymCountLable, asp2CountLable, fiveHtpLable]
for selectedLable in selectedLables {
if selectedLable != "0 s" {
println("You took \(selectedLable[selectedLable.startIndex])")
was working earlier today in a "similar" project, now it gives error
'NSObject' does not have a member named 'startIndex'
so, I tried:
println("You took \(selectedLable[selectedLable.description]) \(keyOfselectedLables)")
which gives a similar error, but ends with ... named 'subscript'
also have tried:
let lable = "rick"
for index in indices(lable) {
print("\(lable[index])")
}
which give error at runtime of : Could not cast value of type 'UILable' (0x199943e30) to 'NSString' (0x198fb2768).
See the below code, selectedLables is an array of UILabel's
let selectedLables = [clonCountLable, baclCountLable, ironCountLable, gymCountLable, asp2CountLable, fiveHtpLable]
but in the if statement you are equating selectedLable, of type UILabel, with a string constant.
for selectedLable in selectedLables {
if selectedLable != "0 s"
Since selectedLable is not a string type, it does not have a startIndex property or index.
So i think the array should be
let selectedLables = [baclCounterLableItem, ironCountLableItem, gymCountLableItem, asp2CountLableItem, fiveHtpLableItem]
Nitheesh George nailed it. (the last answer I see here.) Sorry if I messed up the flow here, total nube.

Resources