How to make a button reset to default state? - swift

I have a button that has 2 switch statements.
buttonPressed() {
switch 1
switch 2
}
Switch 1 checks for errors. If no errors are found, Switch 2 executes. This part works great.
The problem is, when an error is found, on the second press of the button, switch 1 is skipped.
How do I make the button always execute from the start every time it is pressed?
It's as if it creates a breakpoint at the end of the switch, and the second press continues from that breakpoint.
Here's an excerpt of the switch1:
case 1:
let oneLength = countElements(textOne.text)
if oneLength <= 1 {
self.shouldSave = false
showAlertWithText(message: "First checklist item must have a value")
} else if oneLength >= 141 {
self.shouldSave = false
showAlertWithText(message: "First checklist item exceeds the 140 character limit")
} else {
newChecklistOne["goalID"] = self.dependantGoalID
newChecklistOne["itemDescription"] = textOne.text
newChecklistOne["isComplete"] = false
}
switch 2 example:
if self.shouldSave == true {
while self.saveVarTwo <= self.z {
switch self.saveVarTwo {
case 1: newChecklistOne.saveInBackground()
Here's the showAlertWithText function:
func showAlertWithText (header : String = "Ermahgerd!!!", message : String) {
var alert = UIAlertController(title: header, message: message, preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
}
So, how do I make the button start executing code from line 1 on every button click?

So, I had a "saveVar" that worked as the switch catalyst for switch 1. It would iterate to the # of entries, but I never reset it when an error occurred. Therefore, when the button was pressed, the switch started at the max case.

Related

How to know when to call a closure with () or without parentheses in handler:

I have this code:
func askQuestion(action : UIAlertAction! = nil){
countries.shuffle()
correctAnswer = Int.random(in: 0...2)
button1.setImage(UIImage(named: countries[0]), for: .normal)
button2.setImage(UIImage(named: countries[1]), for: .normal)
button3.setImage(UIImage(named: countries[2]), for: .normal)
title = countries[correctAnswer].uppercased()
}
#IBAction func buttonTapped(_ sender: UIButton) {
var title:String
if sender.tag == correctAnswer{
title = "Correct"
score += 1
} else {
title = "Wrong"
score -= 1
}
let ac = UIAlertController(title: title, message: "Your score is \(score)",
preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "Continue", style: .default, handler: askQuestion))
1.In last row how do i know when i need to add parentheses to closure ?
2.Do i always have to add
(action : UIAlertAction! = nil) to askQuestion func when calling closure to handler?
In last row how do i know when i need to add parentheses to closure ?
The question makes no sense. Add what parentheses?
The handler: parameter value is a function. You can supply it in two ways:
A function reference. That is what you are doing (correctly): you have used func to define the function elsewhere, and now you are giving the name of the function as a reference. You do not put parentheses here; that would call the function. You just want to say what function it is.
An anonymous function. That is curly braces. You can give this in two ways:
Directly as the handler: parameter
Using trailing closure syntax
So, the following are all correct:
ac.addAction(
UIAlertAction(
title: "Continue", style: .default, handler: askQuestion))
or
ac.addAction(
UIAlertAction(
title: "Continue", style: .default, handler: { _ in
self.countries.shuffle()
// ...
}
))
or
ac.addAction(
UIAlertAction(
title: "Continue", style: .default) { _ in
self.countries.shuffle()
// ...
}
)
Do i always have to add (action : UIAlertAction! = nil) to askQuestion func
No, I don't understand the point of that at all. Just say _: UIAlertAction if using a defined func. Note the syntax for the anonymous function examples, which is different.
You add parentheses to a function when you call it, not when you pass a reference to it (unless it itself is generating the desired function when it is called).
You need the “action : UIAlertAction” part in this case because your function’s type has to match the expected type of the handler. The ! = nil part is unnecessary because UIAlertAction is not optional (it isn’t followed by a ?, so the compiler knows that it shouldn’t be nil). Better yet, put _: UIAlertAction because you are not using the parameter so it doesn’t need a name.

Realm Item appears twice when added to Table View

I am developing an app where you can add items to a Table View using the Realm Database. At the moment, I can add an Item to the Table View but it's being added twice to the Realm Database. This then means that if I shut my app & then go back into it, the new Item I had previously added appears twice, once in the new position & once replacing the item which was in the table view just above it. Attached is my code. I've tried various different things but just can't figure out how to fix it. Thank you for your help!
This is the code where I am adding the item to my Table View/Realm Database:
extension MainTableViewController {
func createNewEventAlertView () {
let newEventAlert = PMAlertController(title: "New Event Alert", description: "", image: nil, style: .alert)
newEventAlert.addTextField { (eventNameAlertTextField) in
eventNameAlertTextField?.placeholder = "Event Name"
eventNameAlertTextField?.adjustsFontSizeToFitWidth = true
eventNameAlertTextField?.textAlignment = .center
eventNameAlertTextField?.text! = nameOfEvent.text!
nameOfEvent = eventNameAlertTextField!
}
newEventAlert.addTextField { (dayEventDateTextField) in
dayEventDateTextField?.placeholder = "Day Of The Month"
dayEventDateTextField?.inputView = dayPickerView
dayOfEvent = dayEventDateTextField!
}
newEventAlert.addTextField { (monthEventDateTextField) in
monthEventDateTextField?.placeholder = "Month"
monthEventDateTextField?.inputView = monthPickerView
monthOfEvent = monthEventDateTextField!
}
newEventAlert.addTextField { (remindOneDayBeforeTextField) in
remindOneDayBeforeTextField?.placeholder = "Remind 1 Day Before?"
remindOneDayBeforeTextField?.inputView = oneDayPickerView
oneDayReminder = remindOneDayBeforeTextField!
}
newEventAlert.addTextField { (remindSevenDaysBeforeTextField) in
remindSevenDaysBeforeTextField?.placeholder = "Remind 7 Days Before?"
remindSevenDaysBeforeTextField?.inputView = sevenDayPickerView
sevenDayReminder = remindSevenDaysBeforeTextField!
}
newEventAlert.addAction(PMAlertAction(title: "Add", style: .default, action: {
print("Add Event Button Pressed in Alert")
//Adding realmEventItem & its variables to the Database
try! realm.write {
//Adding the name & date of the Event to the Realm Database Item
self.realmEventItem.nameOfEventRealm = self.nameOfEvent.text!
let fullDateOfEvent = self.dayOfEvent.text! + " " + self.monthOfEvent.text!
self.realmEventItem.dateOfEventRealm = fullDateOfEvent
//Telling the Realm Database whether they wan't to be reminded one & seven days before the event
if self.oneDayReminder.text == "Yes" {
self.realmEventItem.oneDayBeforeReminderRealm = true
} else {self.realmEventItem.oneDayBeforeReminderRealm = false}
if self.sevenDayReminder.text == "Yes" {
self.realmEventItem.sevenDaysBeforeReminderRealm = true
} else {self.realmEventItem.sevenDaysBeforeReminderRealm = false}
// Making Sure there is something written in the Name & Date Text Fields before allowing anything to be added
if self.nameOfEvent.text != "" && self.dayOfEvent.text != "" && self.monthOfEvent.text != "" {
/*
- use create method instead of add method to add new entries,
- Because add method replaces last new entry with our previous entry,
- so every time only one object store in database
*/
realm.create(RealmEventItem.self, value: self.realmEventItem, update: false)
self.tableView.insertRows(at: [IndexPath.init(row: realmEventList.count-1, section: 0)], with: .automatic)
//By Adding the follwing line it has meant that my code no longer crashes when I add an Item, then delete it & then try and add another item again.
self.tableView.numberOfRows(inSection: realmEventList.count)
print(realmEventList.count)
self.labelWhenTableViewIsEmpty.text = ""
print("Add to Table View Called")
} else {
// Missing Boxes
print("Missing Information!")
}
// This makes sure that each time the user goes to add a new Event all the picker are reset
if self.nameOfEvent.text != "" { self.nameOfEvent.text = "" }
if self.dayPickerView.selectedRow(inComponent: 0) != 0 { self.dayPickerView.selectRow(0, inComponent: 0, animated: false) }
if self.monthPickerView.selectedRow(inComponent: 0) != 0 {self.monthPickerView.selectRow(0, inComponent: 0, animated: false)}
if self.oneDayPickerView.selectedRow(inComponent: 0) != 0 {self.oneDayPickerView.selectRow(0, inComponent: 0, animated: false)}
if self.sevenDayPickerView.selectedRow(inComponent: 0) != 0 {self.sevenDayPickerView.selectRow(0, inComponent: 0, animated: false)}
}
print("REAL DATA:::-- \(realm.objects(RealmEventItem.self))")
}))
newEventAlert.addAction(PMAlertAction(title: "Cancel", style: .cancel, action: {
print("Cancel Button Pressed in Alert")
}))
present(newEventAlert, animated: true, completion: nil)
}
}
I have managed to fix the problem by using a new variable of type RealmEventItem()
The Code Changed (which is inside try! realm.write) is now as follows:
try! realm.write {
//The concept of adding a newEventItem of type RealmEventItem() & and then adding all the values to it rather than direct to the RealmEventItem() fixed the problem of the new items replacing the previous ones.
let newEventItem = RealmEventItem()
// Joining the Day & Month Together
let fullDateOfEvent = self.dayOfEvent.text! + " " + self.monthOfEvent.text!
// Making Variables to give a boolean of whether the user would like reminders
var oneDayReminderItem = false
var sevenDayReminderItem = false
if self.oneDayReminder.text == "Yes" {
oneDayReminderItem = true
} else {oneDayReminderItem = false}
if self.sevenDayReminder.text == "Yes" {
sevenDayReminderItem = true
} else {sevenDayReminderItem = false}
//Setting the values to the newEventItem --> which is part of the RealmEventItem()
newEventItem.nameOfEventRealm = self.nameOfEvent.text!
newEventItem.dateOfEventRealm = fullDateOfEvent
newEventItem.oneDayBeforeReminderRealm = oneDayReminderItem
newEventItem.sevenDaysBeforeReminderRealm = sevenDayReminderItem
// Making Sure there is something written in the Name & Date Text Fields before allowing anything to be added
if self.nameOfEvent.text != "" && self.dayOfEvent.text != "" && self.monthOfEvent.text != "" {
/*
- use create method instead of add method to add new entries,
- Because add method replaces last new entry with our previous entry,
- so every time only one object store in database
*/
//realm.add(newEventItem, update: false)
realm.create(RealmEventItem.self, value: newEventItem, update: false)
self.tableView.insertRows(at: [IndexPath.init(row: realmEventList.count-1, section: 0)], with: .automatic)
//By Adding the following line it has meant that my code no longer crashes when I add an Item, then delete it & then try and add another item again.
self.tableView.numberOfRows(inSection: realmEventList.count)
print(realmEventList.count)
self.labelWhenTableViewIsEmpty.text = ""
print("Add to Table View Called")
} else {
// Missing Boxes
print("Missing Information!")
}
}
Hope this can help someone in the future!

UITest compare value of element in expectation

I am currently trying to figure out when an activity indicator is on or off. I realised that, when on, its value is 1, 0 when off.
I am trying to check if that value is 1 or 0 like this:
let app = XCUIApplication()
let predicate = NSPredicate(format: "value == 0")
let expectation = expectation(
for: predicate,
evaluatedWith: app.activityIndicators["activityId"],
handler: nil)
if XCTWaiter().wait(for:[expectation], timeout: 20) == .completed {
print ("Activity indicator is off")
} else {
print ("Activity indicator is on")
}
The current problem is that the timeout is always reached. Whenever I set a breakpoint at the if and type this in the console:
po app.activityIndicators["activityId"].value
The result is:
Optional<Any>
- some : 0
However, after I let the test run again, the timeout is reached and the else branch is taken.
Can anyone see what I am doing wrong while accessing the value of the element in the expectation?
Thanks for your help in advance.
Assuming you've both launched your app and set the accessibility identifier of your activity indicator correctly (which it seems you've done), the reason your code doesn't work is that value is a string, not an integer.
Replacing your predicate with the following will make your code work:
let predicate = NSPredicate(format: "value == \"0\"")

One button for several actions

I am having trouble configuring a button that:
1st press will do action 1
2nd press will do action 2
3rd press will do action 3
4th press will do action 1
5th press will do action 2
...and so on
Is there any way to configure that button?
Thanks
If you were interested in keeping track of the number of clicks while also doing the job of the 3 alternating tasks:
var counter : Int = 0
#IBAction func buttonClicked(_ sender: Any) {
counter+=1
//print(counter)
switch counter % 3 {
case 1:
// First Action
case 2:
// Second Action
default:
// Third Action
}
}
Do as below in your button action:
var counter = 0
#IBAction func buttonTapped(_ sender: Any) {
counter += 1
switch counter {
case 1:
// do your action
case 2:
// do your action
case 3:
// do your action
counter = 0
default:
break
}
}

How to wait for a label to appear with character count greater than zero UI Test

Actually before api call only Label is visible with empty text. After getting response label character count is greater than zero. But here how can wait for label appear with character count greater than zero and perform some action.
This is the code I used but I am getting predicate error
caught “NSUnknownKeyException” , “[<_NSCFString 0xjel990> valueForUndefinedKey:]: this is not key value coding-complaint for the key characters
func testForWishListCountIsReflecting() {
let app = XCUIApplication()
app.decide()
cellTap()
app.navigationBars["MMRecoPageView"].buttons["MenuButton"].tap()
let wishListLable = app.staticTexts["WishListLabel"]
wishListLable.label.characters
let exists = NSPredicate(format: "label.characters.count > 0")
expectationForPredicate(exists, evaluatedWithObject:wishListLable, handler: nil)
waitForExpectationsWithTimeout(30, handler: nil)
let expectedValue:String = app.staticTexts["WishListLabel"].value as! String
app.buttons["Wishlist"].tap()
XCTAssertTrue(app.tables.cells.count == UInt(expectedValue))
}
Your issue is in the error message. The characters() selector cannot be used in an NSPredicate because it does not work with KVO.
this is not key value coding-compliant for the key characters
I suggest a slightly different approach. Do you know what the actual text should be? If so, you can change your predicate to match exactly for that. You can remove manually set the "WishListLabel" accessibility and let the content set it automatically.
func testForWishListCountIsReflecting() {
// ...setup...
let wishListLabel = app.staticTexts["contents of label"]
waitForElementToAppear(wishListLabel)
}
private func waitForElementToAppear(element: XCUIElement, file: String = __FILE__, line: UInt = __LINE__) {
let existsPredicate = NSPredicate(format: "exists == true")
expectationForPredicate(existsPredicate, evaluatedWithObject: element, handler: nil)
waitForExpectationsWithTimeout(5) { (error) -> Void in
if (error != nil) {
let message = "Failed to find \(element) after 5 seconds."
self.recordFailureWithDescription(message, inFile: file, atLine: line, expected: true)
}
}
}