Swift how to wait until a value changes - ios

I am writing an application which tests your ability in Classical Greek. And I have a few View Controllers. In the test view controller, I have a huge Begin button, which when pressed initiates a sequence of code, as follows:
#IBAction func test(_ sender: Any) {
beginBtn.isHidden = true
beginBtn.isEnabled = false
answerOne.isHidden = false
answerTwo.isHidden = false
answerThree.isHidden = false
answerFour.isHidden = false
data.currentNumOQue = (data.qCQ + data.qWQ + data.qSQ)
if data.chooseCAlertDataLoaded == false {
data.chooseCharacterQuestionType.addAction(data.chooseCharacterQuestionTypeEngGrk)
data.chooseCharacterQuestionType.addAction(data.chooseCharacterQuestionTypeGrkEng)
data.chooseCAlertDataLoaded = true
} else {
print("not first question")
}
while data.currentQC <= data.qCQ {
present(data.chooseCharacterQuestionType, animated: false, completion: nil)
DispatchQueue.global(qos: .background).async {
while data.chooseCAlertReturnsEngGrk == nil {
}
DispatchQueue.main.sync {
if data.chooseCAlertReturnsEngGrk == true {
//Eng-Grk QUestion
data.chooseCAlertReturnsEngGrk = nil
} else {
//Grk=Eng QUestion
data.chooseCAlertReturnsEngGrk = nil
}
}
}
data.currentQC += 1
data.currentQ += 1
}
data.currentQC = 1
data.currentQW = 1
data.currentQS = 1
}
Can anyone help me in how to wait until the value chooseCAlertReturnsEngGrk is not nil and execute on, but not 'freezing' the UI when doing so?

Override didSet to call some function.. then in that callback function, do whatever you want with the parameter..
class DataSomething {
var chooseCAlertReturnsEngGrkObserver: ((_ newValue: SomeTime?) -> Void)?
var chooseCAlertReturnsEngGrk: SomeType? = nil {
didSet {
chooseCAlertReturnsEngGrkObserver?(chooseCAlertReturnsEngGrk)
}
}
}

Related

Async await swift ui

I have the following code, I would like to use async-await for the two calls.
At the moment inside the function I used a kind of check variable, which when both are set the code is executed.
How can I do?
....
.onAppear {
DispatchQueue.global(qos: .background).async {
getRemoteHead(url: repoUrlStr)
getRemoteBranch(url: repoUrlStr)
}
}
func getRemoteHead(url: String) {
do {
let branch = try Remote().getRemoteHEAD(url: url)
if branch[0].contains("fatal:") {
Log.warning("Error: getRemoteHead")
activeSheet = .error("Error: getRemoteHead")
} else {
self.mainBranch = branch[0]
self.selectedBranch = branch[0]
self.check += 1
if check == 2 {
check = 0
activeSheet = .select
}
}
} catch {
Log.error("Failed to find main branch name.")
}
}
func getRemoteBranch(url: String) {
do {
let branches = try Remote().getRemoteBranch(url: url)
if branches[0].contains("fatal:") {
Log.warning("Error: getRemoteBranch")
activeSheet = .error("Error: getRemoteBranch")
} else {
self.arrayBranch = branches
self.check += 1
if check == 2 {
check = 0
activeSheet = .select
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
// Force a UI Update.
allBranches.toggle()
}
}
}
} catch {
Log.error("Failed to find branches.")
}
}

How to Hide specific UIButtons based on String contained in Array

I have some UIButtons that represents different Restaurants the content comes from a struct. In this struct is an Array with Tags for each Restaurant.
How can I hide a UIButton based on the Tags?
At the moment I have this in an provisionally way:
func filterFavorites() {
if importedDataA.filterTags.contains(filterPresetRestaurantTypeService) {
isVisibleA = true
} else {
isVisibleA = false
}
if importedDataB.filterTags.contains(filterPresetRestaurantTypeService) {
isVisibleB = true
} else {
isVisibleB = false
}
if importedDataC.filterTags.contains(filterPresetRestaurantTypeService) {
isVisibleC = true
} else {
isVisibleC = false
}
if importedDataD.filterTags.contains(filterPresetRestaurantTypeService) {
isVisibleD = true
} else {
isVisibleD = false
}
if importedDataE.filterTags.contains(filterPresetRestaurantTypeService) {
isVisibleE = true
} else {
isVisibleE = false
}
if importedDataF.filterTags.contains(filterPresetRestaurantTypeService) {
isVisibleF = true
} else {
isVisibleF = false
}
if importedDataG.filterTags.contains(filterPresetRestaurantTypeService) {
isVisibleG = true
} else {
isVisibleG = false
}
etc...
And...
func filterApply() {
if isVisibleA == true {
if UserDefaults.standard.bool(forKey: "hideFilteredObjects") == true {
cellA.isHidden = false
} else {
//cellA.popIn()
}
} else {
if UserDefaults.standard.bool(forKey: "hideFilteredObjects") == true {
cellA.isHidden = true
} else {
//cellA.popOut()
}
}
}
Instead of creating several instances of your struct importedDataA, importedDataB, importedDataC, etc., you can just create an array of instances something like:
var importedData: [your-structure] = []
Then instead of going through all of these items one by one with an if statement, you can use a for loop to go through these instances like:
for data in importedData{
if data.filterTags.contains(filterPresetRestaurantTypeService){
isVisibleG = true
} else {
isVisibleG = false
}
}
Assume you have a struct:
struct ImportedData{
var filterTags: [Int]
}
let buttons = [UIButton]() // add your buttons
let importedData = [ImportedData]() // add your importedData
(0..<(buttons.count)).map{buttons[$0].isHidden = UserDefaults.standard.bool(forKey: "hideFilteredObjects") && (!importedData[$0].filterTags.contains(filterPresetRestaurantTypeService))}

how to delay for loop iterations in swift

i have write the follwing code for my function but i failed to execute iterations after delaying.
I want iterations with delay, for example when loop completed execution till i =2 after this when i == 3 this should execute after some delay.
Please guide me to solve this problem.
func allCellsAttempted() -> Bool {
var allCellsAttempted = true
var count = 0
if !oldVersionTriggered {
count = micSources.count
}
else {
count = olderVersionMicSources.count
}
print("Total Mics : \(count)")
for i in 0..<count {
if let cell = micTestFaliureTableView.cellForRow(at: IndexPath(row: i, section: 0)) as? MicFaliureTableViewCell {
if !cell.micFaliureTestview.attempted {
allCellsAttempted = false
break
}
}
}
return allCellsAttempted
}
You could use a timer. You will need to pass a completion handler closure to your function to access the result.
I would also suggest you access the information from the underlying data model rather than from the table view cells.
func allCellsAttempted(_ completion: #escaping(_ attempted: Bool)-> Void) -> Void {
var allCellsAttempted = true
var count = 0
var target: Int
if !oldVersionTriggered {
target = micSources.count
}
else {
target = olderVersionMicSources.count
}
print("Total Mics : \(target)")
let _ = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] (timer) in
guard let strongSelf = self else {
timer.invalidate()
return
}
if let cell = strongSelf.micTestFaliureTableView.cellForRow(at: IndexPath(row: count, section: 0)) as? MicFaliureTableViewCell {
if !cell.micFaliureTestview.attempted {
allCellsAttempted = false
}
}
count += 1
if count == target || !allCellsAttempted {
timer.invalidate()
completion(allCellsAttempted)
}
}
}
Try to use
DispatchQueue.main.asyncAfter(deadline:.now() + 2.0, execute: { })

check the text of the buttons in the array

I have 5 buttons and they are in an array. While text of the buttons unequal to cevapLabel.Text, I want to hide them randomize. how to check all buttons text?
like this;
while allButtonsText != cevapLabel.Text {}
Here is my code:
#IBAction func eliminateChoiceClicked(_ sender: Any) {
let num = Int(arc4random_uniform(5))
let buttons:[UIButton] = [buttonA,buttonB,buttonC,buttonD,buttonE]
while buttons != cevapLabel.text {
buttons[num].isHidden = !buttons[num].isHidden
}
}
in this code its show this error: " Binary operator '!=' cannot be applied to operands of type '[UIButton]' and 'String?' "
---EDITED---
I had to make a few changes in my project.
Here is the code:
#IBAction func eliminateChoiceClicked(_ sender: Any) {
var buttons: [UIButton] = [buttonA,buttonB,buttonC,buttonD,buttonE]
for _ in 1...3 {
let randomNumber = Int(arc4random_uniform(UInt32(buttons.count)))
let button = buttons.remove(at: randomNumber)
button.isHidden = true
}
for button in buttons {
button.isHidden = false
}
}
I tried like this:
#IBAction func eliminateChoiceClicked(_ sender: Any) {
var buttons: [UIButton] = [buttonA,buttonB,buttonC,buttonD,buttonE]
for x in buttons {
if x.titleLabel?.text != cevapLabel.text {
for _ in 1...3 {
let randomNumber = Int(arc4random_uniform(UInt32(buttons.count)))
let button = buttons.remove(at: randomNumber)
button.isHidden = true
}
}
else {
for button in buttons {
button.isHidden = false
}
}
}
}
And i got that error: "Thread 1: Fatal error: Index out of range"
The issue occurs because you're comparing an array of UIButtons with a String.
You can fix your issue by creating a func returning a Bool and calling it in your while statement like so:
#IBAction func eliminateChoiceClicked(_ sender: Any) {
let num = Int(arc4random_uniform(5))
let buttons:[UIButton] = [buttonA,buttonB,buttonC,buttonD,buttonE]
while !isStringContainedInButtons(buttons) {
buttons[num].isHidden = !buttons[num].isHidden
}
}
func isStringContainedInButtons(buttons: [UIButton]) -> Bool {
for (button in buttons) {
if (button.titleLabel?.text == cevapLabel.text) {
return true
}
}
return false
}
I don’t understand the need for the while loop, I would replace it with
if buttons.map($0.title).filter($0 == cevapLabel.text).count == 0 {
buttons[num].isHidden = !buttons[num].isHidden
}
Swift 4
for button in buttons {
if button.title(for: .normal) == cevapLevel.text {
//your code
}
}

how to check all fields in the array contains data

I want to check the array to see if all the fields have a value, and if all the fields have a value, then I want it to do something. My code does work but it is really messy. I'd like to know if there is an easier way of doing this.
#IBAction func testBtn(sender: AnyObject) {
self.textData = arrayCellsTextFields.valueForKey("text") as! [String]
for item in textData {
if item.isEmpty {
print("Missing")
switchKey = true
// alertviewer will go here
break
} else {
switchKey = false
}
}
if switchKey == false {
//navigation here
print("done")
}
}
You can do this with the filterfunction
if textData.filter({$0.isEmpty}).count > 0 {
// there is at least one empty item
} else {
// all items contain data
}
Try this combination of guard and .filter:
#IBAction func testBtn(sender: AnyObject) {
self.textData = arrayCellsTextFields.valueForKey("text") as! [String]
guard textData.count == (textData.filter { !$0.isEmpty }).count else {
print("Missing")
return
}
print("Done")
}

Resources