How can I remove repetitive code in swift? - swift

I have 2 sections and 6 lines of code that do the opposite things for an app that I have made for a project. The code was typed as it was taught to us, but in the project review I was told to get rid of the repetitive/like code. Can anyone help point me in the right direction with this? Thanks
#IBAction func stopRecording(_ sender: AnyObject) {
recordButton.isEnabled = true
stopRecordingButton.isEnabled = false
recordingLabel.text = "Tap to Record"
}
#IBAction func recordAudio(_ sender: AnyObject)
{
recordingLabel.text = "Recording in Progress"
stopRecordingButton.isEnabled = true
recordButton.isEnabled = false
}

You can also do this by didSet Observer.
var isRecording: Bool = false {
didSet {
recordButton.isEnabled = !isRecording
stopRecordingButton.isEnabled = isRecording
recordingLabel.text = isRecording ? "Recording in progress" : "Tap to Record"
}
}
And the actions become pretty simple like this.
#IBAction func stopRecording(_ sender: AnyObject) {
isRecording = false
}
#IBAction func recordAudio(_ sender: AnyObject) {
isRecording = true
}

Related

How to refer #IBAction Func to several button outlets

I have lots of buttons that when pressed run very similar code, im currently writing a function for each, is there a way to compact this to one function?
Heres some of the code:
#IBAction func b0(_ sender: UIButton) {
if pressedArray[0] && buttonsCanBePressed {
pressedArray[0] = false
b0.backgroundColor = notPressedColour
} else if buttonsCanBePressed {
b0.backgroundColor = pressedColour
pressedArray[0] = true
}
}
#IBAction func b1(_ sender: UIButton) {
if pressedArray[1] && buttonsCanBePressed {
pressedArray[1] = false
b1.backgroundColor = notPressedColour
} else if buttonsCanBePressed {
b1.backgroundColor = pressedColour
pressedArray[1] = true
}
}
#IBAction func b2(_ sender: UIButton) {
if pressedArray[2] && buttonsCanBePressed {
pressedArray[2] = false
b2.backgroundColor = notPressedColour
} else if buttonsCanBePressed {
b2.backgroundColor = pressedColour
pressedArray[2] = true
}
}
Yes, You can make only one IBAction function, and then drag the circle in the line number to all the buttons you want, and you can differentiate the buttons using sender.tag

Automatically delete data from Firebase Database

I have seen some other questions asked but I am having trouble getting it to work. I have a Mac app coded in swift and it has a Firebase login but the user types a key in that is stored on Firebase, is there a way to automatically delete that key when the user has successfully used it?
This is my database.
This is the code that is used currently.
import Cocoa
import FirebaseAuth
import FirebaseDatabase
class LoginViewController: NSViewController {
#IBOutlet weak var textUsername: NSTextField!
#IBOutlet weak var textPassword: NSSecureTextFieldCell!
#IBOutlet weak var btnLogin: NSButton!
var keyArray = \[Int64\]()
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear() {
}
func getLoginState() -> Bool{
let state = UserDefaults.standard.bool(forKey: "isRegistered")
if (state) {
return true
} else {
return false
}
}
override func viewDidAppear() {
let state = self.getLoginState()
if (state){
self.performSegue(withIdentifier: NSStoryboardSegue.Identifier(rawValue: "loginsegue"), sender: nil)
self.view.window?.close()
}
var ref: DatabaseReference!
ref = Database.database().reference()
let keyRef = ref.child("key1")
keyRef.observe(DataEventType.childAdded, with: { (snapshot) in
// let postDict = snapshot.value as? \[String : AnyObject\] ?? \[:\]
let keyStr = snapshot.value as? Int64
if let actualPost = keyStr{
self.keyArray.append(actualPost)
}
})
}
#IBAction override func dismissViewController(_ viewController: NSViewController) {
dismiss(self)
}
#IBAction func close(sender: AnyObject) {
self.view.window?.close()
}
#IBAction func onSignup(_ sender: Any) {
// self.performSegue(withIdentifier: NSStoryboardSegue.Identifier(rawValue: "gotosignup"), sender: sender)
// self.view.window?.close()
}
func dialogOK(question: String, text: String) -> Void {
let alert: NSAlert = NSAlert()
alert.messageText = question
alert.informativeText = text
alert.alertStyle = NSAlert.Style.warning
alert.addButton(withTitle: "OK")
alert.runModal()
}
#IBAction func onLogin(_ sender: Any) {
//self.btnLogin.isEnabled = false
var isKey = false
if (!self.textUsername.stringValue.isEmpty) {
for key in keyArray{
if(Int64(self.textUsername.stringValue)! == key)
{
UserDefaults.standard.set(true, forKey:"isRegistered")
self.performSegue(withIdentifier: NSStoryboardSegue.Identifier(rawValue: "loginsegue"), sender: nil)
self.view.window?.close()
isKey = true
}
}
if (!isKey){
self.dialogOK(question: "Error", text: "Invalid Key")
}
} else {
self.dialogOK(question: "Error", text: "Please Input Key")
}
}
}
You can't sort your database like that and expect a working code, even if there's any. It will make a messy code:
You need to:
Sort your database like [1220:0]. the key first. 0 & 1 as an indicator if it's used or not.
Once the user taps onLogin() you need to set the used key value to 1
Setup Cloud Functions to check if the used key is equal to 1, if yes. then remove the key.
Do the rest of the work.
Related Articles to get you started:
Extend Realtime Database with Cloud Functions
functions.database.RefBuilder

Unresolved Identifier 'count'

Here is the error that I am seeing.
The "cardButton" is responsible for showing the next question. This is a small card app game that I am trying to make and as you can see from the image this is where I am having the issue with the code.
Here is the code:
import UIKit
class MultipleViewController: UIViewController {
#IBOutlet weak var questionLabel2: UILabel!
#IBOutlet var answerButtons: [UIButton]!
#IBOutlet weak var cardButton: UIButton!
#IBAction func cardButtonHandle(_ sender: Any) {
cardButton.isEnabled = true
if questionIdx < count(mcArray) - 1 { // There are still more questions
questionIdx += 1 //
} else {
questionIdx = 0
}
nextQuestion()
}
#IBAction func answerButtonHandle(_ sender: UIButton) {
if sender.titleLabel?.text == correctAnswer{
sender.backgroundColor = UIColor.green
print("Correct!")
} else {
sender.backgroundColor = UIColor.red
print("Wrong Answer")
}
for button in answerButtons{
button.isEnabled = false
if button.titleLabel?.text == correctAnswer {
button.backgroundColor = UIColor.green
}
}
cardButton.isEnabled = true // next question
}
var correctAnswer: String? // correct answers
var answers = [String]() // answers
var question : String? // Questions
var questionIdx = 0 // not sure what this is ?
override func viewDidLoad() {
super.viewDidLoad()
// titleForButtons() // call buttons as soon its loaded..
cardButton.isEnabled = false
nextQuestion()
}
func nextQuestion (){
let currentQuestion = mcArray![questionIdx]
answers = currentQuestion["Answers"] as! [String]
correctAnswer = currentQuestion["CorrectAnswer"] as? String
question = currentQuestion["Question"] as? String
titleForButtons ()
}
func titleForButtons (){
for (idx,button) in answerButtons .enumerated() {
button.titleLabel?.lineBreakMode = .byWordWrapping
button.setTitle(answers[idx],for:.normal)
button.isEnabled = true
}
questionLabel2.text = question
}
}
The following should work, you did not have the correct syntax for the length of the array. Note that if you have not initialized your questions array, this would cause a crash. Therefore you might want to add a guard into your code. Perhaps use the following
#IBAction func cardButtonHandle(_ sender: Any) {
cardButton.isEnabled = true
if questionIdx < (mcArray!.count) - 1 { // There are still more questions
questionIdx += 1 //
} else {
questionIdx = 0
}
nextQuestion()
}

Swift Segmented Control

I made a segmented control in swift that changes a boolean to either true or false; However, every time I select "selectedSegmentedIndex == 1" in the application, I get error "Thread 1: signal SIGABERT"
My code goes as flows:
#IBOutlet weak var translationType: UISegmentedControl!
var state = true
#IBAction func translation(_ sender: Any)
{
if translationType.selectedSegmentIndex == 0
{
state = ture
}
else if translationType.selectedSegmentIndex == 1
{
state = false
}
}
Any information would be greatly appreciated. Thanks.
At least using the sender parameter and the static type avoids the crash if translationType is not connected – which is most likely the case.
#IBAction func translation(_ sender: UISegmentedControl)
{
if sender.selectedSegmentIndex == 0
{
state = true
}
else if sender.selectedSegmentIndex == 1
{
state = false
}
}
or a bit shorter
#IBAction func translation(_ sender: UISegmentedControl)
{
state = sender.selectedSegmentIndex == 0
}
var state = true
#IBOutlet weak var translationType: UISegmentedControl!
#IBAction func translation(_ sender: UISegmentedControl)
{
if translationType.selectedSegmentIndex == 0
{
state = true
}
else if translationType.selectedSegmentIndex == 1
{
state = false
}
print(state)
print(translationType.selectedSegmentIndex)
}
make sure your outlet is connected! see connection inspector

If (Bools = true) not executing -Swift

Attempting to execute a modal segue when multiple different Bool variables are all true (activated true through IBAction button push), however, nothing is happening- here is how they are all setup-
UIViewController {
// INITIAL TO CHECK WHICH BUTTONS HAVE BEEN PUSHED //
var 1Check = Bool()
// Checks //
#IBAction func 1(_ sender: AnyObject) {
1Check = true
}
and here is the execution-
viewDidLoad() {
super.viewDidLoad()
MoveOn()
}
func MoveOn(){
if (1Check == true && 2Check == true ...) {
self.performSegue(withIdentifier: "NewScreen", sender: nil)
}
}
what am I missing? Thanks!
The call to MoveOn() needs to be in a place where it will be called every time one of those checked values changes:
UIViewController {
// INITIAL TO CHECK WHICH BUTTONS HAVE BEEN PUSHED //
var 1Check = Bool()
// Checks //
#IBAction func 1(_ sender: AnyObject) {
1Check = true
MoveOn()
}
viewDidLoad() {
super.viewDidLoad()
}
func MoveOn(){
if (1Check == true && 2Check == true ...) {
self.performSegue(withIdentifier: "NewScreen", sender: nil)
}
}
}