I implemented a button action that switch from one view with a UIlabel.text to another view that will display another specifical label that is corresponding .
The method i am using, at present is as follow:
func switchCard(_ sender: Any) {
if item1.text == "Fabulae"{
item2.text = " expriment"
}
if item1.text == " simulacra"{
item2.text = "finxere"
}
if item1.text == "tergentes"{
item2.text = "icet"
} }
And its working , but I need to repeat so many times a hundred time for each item so i am wondering if it does exist a simpler way
I was thinking to build to variables with my labels for item 1 and Item2 so they will share the same index and implement a single statement that will make swift able to pick up the right content when i am cliking on the button.
I am going in the correct way ?
Thank you in advance to read me and your kind help .
Regards,
Try this:
enum TypeName: String {
case fabulae = "Fabulae"
case simulacra = " simulacra"
case tergentes = "tergentes"
func getNeededText() -> String {
switch self {
case .fabulae: return " expriment"
case .simulacra: return "finxere"
case .tergentes: return "icet"
}
}
}
func switchCard(_ sender: Any) {
item2.text = TypeName(rawValue: item1.text ?? "")?.getNeededText()
}
OR you can use a dictionary:
let pairs = ["Fabulae": " expriment", " simulacra": "finxere", "tergentes": "icet"]
func switchCard(_ sender: Any) {
item2.text = pairs[item1.text]
}
Related
I am implementing button click to add CollectionView Cell like a Tag UI. Here, I created TagModel class for maintaining TagId and validating each time the tag data available or not by using if items.contains(tag) == false {….} (It will avoid duplication into collection view). Now, I need to add one more validation into this, if items.contains(tag) == true need to check tagName and current selected values are same. if not same I need to replace that tag value. How to achieve this?
Tag Validation Code
func tagValidation(){
// Validate A
if let aValue = UserDefaults.standard.object(forKey: "a") as? [String:Any] {
let tag = TagModel(dict: aValue)
if items.contains(tag) == false { // how to check if true need to validate current value and already exists values are same. if same no need to replace or else need to replace value
items.append(tag)
}
}
}
First ViewController
#IBAction func saveAction(_ sender: Any) {
let tag = TagModel(tagId: 0, tagName: "test", tagStoreKey: "a")
tag.save()
self.dismiss(animated: true, completion: nil)
}
Something is not right with your equality operator: you are asking if two items are the same - and if they are the same then check if something in them is different :)
Try to search array with first method: if you find (and you will) any item matching the case continue with your work.
Something like this:
if let aValue = UserDefaults.standard.object(forKey: "a") as? [String:Any] {
let tag = TagModel(dict: aValue)
if items.contains(tag) == false {
items.append(tag)
} else if let existing = items.first(where: { $0 == tag}), existing.tagName != tag.tagName {
// replace item
let index = items.firstIndex(of: tag)!
items[index] = tag
}
}
So I'm working on a quiz-app and I want to give the user an option screen before starting the quiz, where the user can choose which categories the quiz should have.
Its currently only working with 1 category at a time but I want to be able to concatenate the questionArrays when the user selects button in the option screen.
At this time the user selects a button and depending on the sender.tag an Int gets passed through the var called 'pickedCategory' which then decides which of the arrays to base the questions on. This happens in the prepare for segue:
let selectedCategory = quizCategories[pickedCategory]
secondVC.allQuestions = selectedCategory.questions
quizCategories is declared at the top:
var quizCategories = [QuestionArray]()
What I would like to do is have 4 buttons and whenever one is selected, concatenate an array to the selectedCategory
For instance, button 1 & 2 is selected, i.e. the user wants to have questions based on 2 categories. Resulting in something like this?
let selectedCategory = quizCategories[0].questions + quizCategories[1].questions
and if 3 buttons selected, add another quizCategories array to the final array etc etc
Please note, its not HOW to concatenate I'm looking for, its how to automatically do this depending on buttons selected..
This is my first question posted and I am very new to Swift.. hope I didn't confuse u guys.. thanks :)
What I would suggest is for each category button, keep track of which is selected (and even deselected if the user decides they don't want that category), by adding or removing from an array of categoryIDs. Then, once the "Done" button (or whatever final decision button is tapped), take the array of categoryIDs they selected, and flatMap over them to produce the ultimate array of questions.
let questions = categoryIDs.flatMap { quizCategories[$0].questions }
Now, you'd have your array of questions to present to the user. Use flatMap vs map, because you'd want to flatten the returned array of arrays into a single array.
Tags are not the best way to identify buttons, but I'll ignore that.
Don't use buttons, use UISwitches. Have a switch for each category.
Say you have a constant switchTagBase, with a value of 100:
let switchTagBase = 100
So the switch for your first category has a tag of 100, the next one has a tag of 101, etc.
You already have an array of categories, which is good.
Now, when it's time to build your array of selected questions, simply go through the categories, figure out which switches are on, and add in those categories
var selectedCategories = [QuestionArray]()
for (index, array) in quizCategories.enumerated() {
let thisTag = index + switchTagBase
guard let thisSwitch = view.viewWithTag(thisTag),
thisSwitch.isOn else { continue }
selectedCategories += quizCategories[index]
}
(Note that you should really maintain an array of selection states based on the switches the user activates, and iterate through that array rather than looping through the switches directly, but in the interest of brevity I fetched switch states directly.)
You can track which button is selected and when you want to start quizz, concatenate the corresponding arrays.
Your code could look like this:
import UIKit
class QuizzSelection: UIViewController
{
#IBAction func firstButtonAction(_ sender: Any)
{
firstButtonWasClicked()
}
#IBAction func secondButtonAction(_ sender: Any)
{
secondButtonWasClicked()
}
#IBAction func goForwardWithQuizz(_ sender: Any)
{
startQuizzWasClicked()
}
var isFirstCategorySelected = false
var isSecondCategorySelected = false
let firstCategoryQuestions = ["Question Cat 1"]
let secondCategoryQuestions = ["Question Cat 2"]
var emptyArrayOfQuestions = [String]()
func firstButtonWasClicked()
{
if isFirstCategorySelected == true{
isFirstCategorySelected = false
} else{
isFirstCategorySelected = true
}
}
func secondButtonWasClicked()
{
if isSecondCategorySelected == true{
isSecondCategorySelected = false
} else{
isSecondCategorySelected = true
}
}
func startQuizzWasClicked()
{
if isFirstCategorySelected == true{
emptyArrayOfQuestions += firstCategoryQuestions
}
if isSecondCategorySelected == true{
emptyArrayOfQuestions += secondCategoryQuestions
}
}
}
EDIT
Improved code for six categories:
import UIKit
class QuizzSelection: UIViewController
{
#IBAction func firstButtonAction(_ sender: Any)
{
firstButtonWasClicked()
}
#IBAction func secondButtonAction(_ sender: Any)
{
secondButtonWasClicked()
}
// Four mour button actions
#IBAction func goForwardWithQuizz(_ sender: Any)
{
startQuizzWasClicked()
}
var wichCategoryAreSelected = [false, false, false, false, false, false] //six categories
var arrayOfQuestions = [["Question 1 Cat 1","Question 2 Cat 1"], ["Question 1 Cat 2", "Question 2 Cat 2"], ...]
var emptyArrayOfQuestions = [String]()
func firstButtonWasClicked()
{
wichCategoryAreSelected[0] = !wichCategoryAreSelected[0]
}
func secondButtonWasClicked()
{
wichCategoryAreSelected[1] = !wichCategoryAreSelected[1]
}
func startQuizzWasClicked()
{
for i in 0...(wichCategoryAreSelected.count-1)
{
if wichCategoryAreSelected[i]
{
emptyArrayOfQuestions += arrayOfQuestions[i]
}
}
}
}
I am creating a wizard using UICollectionView with an array of CollectionViewCells:
var viewCells:[BaseCVCell] = [createEventSubjectSearch(), createEventEventForm()]
This array is dynamically added to based on a series of UISwitch's that the user controls. I can add to the array fine using the code below, however I can't seem to remove an item when a user turns the switch off.
func switchToggled(sender : UISwitch) {
if sender == createDiarySwitch {
if sender.isOn {
parentClass?.viewCells.append(createEventDeferEvent())
} else {
if let i = parentClass?.viewCells.index(where: { $0 == createEventDeferEvent() }) {
parentClass?.viewCells.remove(at: i)
}
}
}
if sender == createDeferredSwitch {
if sender.isOn {
parentClass?.viewCells.append(createEventDiariseEvent())
} else {
if let i = parentClass?.viewCells.index(where: { $0 == createEventDiariseEvent() }) {
parentClass?.viewCells.remove(at: i)
}
}
}
parentClass?.wizardCollectionView.reloadData()
}
I have tried the above code, as well as:
if let index = parentClass?.viewCells.index(of: createEventDiariseEvent()) {
parentClass?.viewCells.remove(at: index)
}
Neither approach works (no errors, the code just never returns a value). I'd like to try and avoid naming elements where possible. Is there a way to do this?
Thanks for your answers, DonMag
I've achieved the desired functionality by instanciating the two dynamic cells in the main class:
let diariseCell : createEventDiariseEvent()
and then in the loop calling as thus:
if sender == createDiarySwitch {
if sender.isOn {
parentClass?.viewCells.append((parentClass?.diariseCell)!)
} else {
if let i = parentClass?.viewCells.index(where: { $0 == parentClass?.diariseCell }) {
print("Found cell reference at index \(i)")
parentClass?.viewCells.remove(at: i)
}
}
}
Works a charm now. Amazing what another pair of eyes can pick out!
I'm pretty new to this so bear with me. What I'm trying to do is check if the button is currently displaying an element from an array; array Answers. What would be the best route to do so?
#IBAction func qButton1(_ sender: Any) {
if (sender as AnyObject).currentTitle == (Answer in Answers){
PickQuestion()
}
else{
missedWords.append(quizLabel.text!)
}
}
Not sure why you pass Any as sender and then cast to AnyObject. Anyway I would use filter in your case:
Suppose you have an array of Answer objects called answers and Answer has a property title
if let _ = answers.filter( { $0.title == (sender as AnyObject).currentTitle) }).first {
PickQuestion()
} else{
missedWords.append(quizLabel.text!)
}
You should not use the button's title to store data and compare it to a value.
Any time you write code who's logic depends on text displayed to the user you are paining yourself into a corner in terms of localization.
Using a numeric tag to index into an array of strings would be a much better idea.
Say you create an array of title strings.
Make each button's tag be 100 + the array index.
let startingTag = 100
#IBAction func qButton1(_ sender: UIButton) {
guard let index = sender.tag where startingTag >= 100 else {
return
}
//fetch your string from the array of button title strings you set up.
let stringToFind = strings[index]
if answers.contains(where: {$0 == stringToFind}) {
//Found the current' buttons' string in answers
} else {
//string not found
}
}
i'm new the forum and also new to the swift language. I've been playing around with xcode and wanted to create an app that uses a fenceloop to display the factors of a number as a "solution." The app currently uses a label to display, a text for input, and a button to initiate. I have what i think to be functioning code but i can't see to get it to work because from what i understand, i have to convert the input that's a string into an int. If anyone has any ideas how to get this working; since i feel like i've done what i can.
The problem in particular i am getting is it is saying that "Cannot convert value of type 'UITextField!; to expected argument type 'Int'. What i intend to happen is that on the button click, it solves for the factors of whatever is in the text box and displays it as a string in the label. Any help is appreciated!
import UIKit
class ViewController: UIViewController {
#IBOutlet var input1 : UITextField!
#IBOutlet var label : UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
#IBAction func printFactors(n: Int) {
var result: String = ""
for i in 1...n {
guard n % i == 0 else {continue}
result += i == 1 ? "1" : " and \(i)"
}
print(result)
let outputText = printFactors(n: input1)
label.text = outputText
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
You have a lot of issues and confusion in your printFactors method. Lets split it up and setup things properly.
First, make a separate method to do the math:
func calculateFactors(n: Int) -> String {
var result: String = ""
for i in 1...n {
guard n % i == 0 else {continue}
result += i == 1 ? "1" : " and \(i)"
}
print(result)
return result
}
Now lets setup the button action:
#IBAction func factorAction(sender: UIButton) {
if let text = input1.text {
if let num = Int(text) {
let factor = calculateFactors(n: num)
label.text = factor
} else {
// Show the user that the entered text isn't a number
}
} else {
// There's no text
}
}
Setup your button to use the new factoryAction: method instead of the old printFactors: method.
Swift 3
Can reduce this code down to two lines with some functional magic.
func factors(of number: Int) -> [Int] {
return (1...number).filter { number % $0 == 0 }
}
print(factors(of: 24))