Brackets appear when you insert a Label in the Array (Swift) - ios

I have code to store a number in an array from a Label.
#IBAction func MSSave(_ sender: UIButton) {
MSarrayResults.removeAll()
if let MSText = displayResultLabel.text {
let result = "\(MSText)"
MSarrayResults.append(result as AnyObject)
print ("\(MSText)")
}
}
Button to display the array on the screen (displayResultLabel)
#IBAction func MRRead(_ sender: UIButton) {
displayResultLabel.text = "\(MSarrayResults)"
}
But when I insert the array into the Label brackets appear (Look Photo).

What you are doing:
displayResultLabel.text = "\(MSarrayResults)"
is setting the text to the "default string representation" of an array. That typically looks like this (if you have 5 numbers in the array):
[5, 7, 85, 13, 9]
or, as you have seen:
[85]
if you have only one number in the array.
Essentially, it is a "human readable" representation.
If you want to set the text to the first element in your array, you can use:
displayResultLabel.text = "\(MSarrayResults.first)"
or:
displayResultLabel.text = "\(MSarrayResults[0])"
However, since your MSSave() function is removing all elements from MSArrayResults before it appends the new string, it doesn't make any sense to use an array when you could simply use a String variable.

Related

How to programmatically receive input from UIButton in Swift 4?

I'm new to Swift. I managed to build an app which almost works, but I cannot get the last steps right. I would appreciate any help!
I wrote a code which displays a user-defined number of UILabels. In those labels, the contents of a [String] is displayed. Under the labels, there is the same number of UITextFields. The user should fill out these text fields, press the button and then see if what he filled out matches the labels.
All the labels, the text fields, and the button are made completely programmatically, so without using the storyboard. In the viewDidLoad there is all the code and this line:
myButton.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
Right under viewDidLoad there is this function which I found on this forum and I changed it a bit:
#objc func buttonAction(sender: UIButton!) -> [String] {
var a = 0
var userInput: [String] = Array()
while a < 4 {
if let myTextField = self.view.viewWithTag(a) as? UITextField {
let tekstInput = myTextField.text
userInput.insert(tekstInput!, at:a-1)
}
a = a + 1
}
return userInput
}
My problems:
The while-loop in the function shouldn't have 4 as the maximum, but a user-defined variable. But if I try to change function so that it expects that variable as an input, I get error messages in the myButton.addTarget line.
How do I read out the return in the viewdidload to add there the code to compare the user input with the original [String]?
You should consider the source of the user-defined input if you want to answer your question.
For instance, if you are willing to add an extra UITextField to retrieve your user input, then all you have to do is extract the value from that text field within your buttonAction(sender:) method and use it there. This translates roughly to the following
#objc func buttonAction(_ sender: UIButton) {
var a = 0
var userInput: [String] = Array()
guard let upperLimit = self.userInputTextField.text as? Int else {
return
}
while a < upperLimit {
if let myTextField = self.view.viewWithTag(a) as? UITextField {
let tekstInput = myTextField.text
userInput.insert(tekstInput!, at: a-1)
}
a = a + 1
}
}
Note that self.userInputTextField is the extra text field you should add in order to retrieve your user-defined input.

How to concatenate arrays when button is selected

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]
}
}
}
}

Save data randomly generated into label

I am fairly new to coding and was wondering if it was possible to save data I have randomly generated into a label. I can randomly generate the data and input it into the label but I am having difficulties saving the previous data from the label to an array. Is it possible to do this? And how would it be done?
Essentially I want the user to be able to go back to the previous text in the label if they press a button
Thank you for any help.
code:
This is how I am generating the random variable from an array which contains quotes
//right hand button tapped
#IBAction func RHSButton(_ sender: Any) {
// randomises variable to display
var randomQuote: String {
let randomNumber = Int(arc4random_uniform(UInt32(myQuotes.count)))
return myQuotes[randomNumber]}
quotesLabel.text = randomQuote
}
I want to be able to store the data into an array called:
var randomGeneratedQuotes : [String] = []
But I am not quite sure how
hi seems like u want undo feature.
take one more array and add selected randomNumber
on clicking button display last index of array and remove it from array.
If I understand you correctly you could save the value of your label into your randomGeneratedQuotes array just before you generate a new random value.
var randomQuote: String {
let randomNumber = Int(arc4random_uniform(UInt32(myQuotes.count)))
return myQuotes[randomNumber]
}
#IBAction func RHSButton(_ sender: Any) {
//If a value is present, save it
if let oldValue = quotesLabel.text {
randomGeneratedQuotes.append(oldValue)
}
//and update the value
quotesLabel.text = randomQuote
}
From your previous questions I'm guessing you'd like a LHSButton function to give you the previous value, that could look like so:
#IBAction func LHSButton(_ sender: Any) {
//Do we have a previous value?
if randomGeneratedQuotes.count > 0 {
//take that
let previousValue = randomGeneratedQuotes.removeLast()
//and use it
quotesLabel.text = previousValue
}
}
Hope that works and helps.

How do I sort Integer values typed into a TextField in Xcode?

I've just started to do some simple programming with Swift, things like building a simple calculator and stuff like that. Now I would like to create an app that allows me to sort a bunch of integer values which the user is typing into the TextField. Down here is what I've got so far. Could you please tell me where my mistake is?
class ViewController2: UIViewController {
#IBOutlet var randomNumbers: UITextField!
#IBOutlet var finalResult: UITextView!
#IBAction func SortNumbers(_ sender: UIButton) {
let sortedNumbers = Int[randomNumbers.text]
let sortedNubers = sortedNumbers.sort{$1>$2}
finalResult.text = String(sortedNumbers)
}
it's not the best answer you could get, but it might solves your problem:
#IBAction func sortNumbers(_ sender: UIButton) {
let stringWithNumbers = "1 23 12 4 5 12"
let sortedNumbers = stringWithNumbers.components(separatedBy: " ").flatMap { Int($0) }
let sortedNubers = sortedNumbers.sorted { $0 > $1 }
print(sortedNubers.description)
}
You're not converting it into an Int array properly. If we can assume that the input string is a comma-separated list with no spaces:
let sortedNumbers = randomNumbers.text.components(separatedBy: ",").map{ Int($0) ?? 0 }
components splits it into a string array using commas as a reference, and then map converts each element into an Int (and ?? 0 catches any invalid input and prevents it from being an array of optionals).
Also, for the sake of your sanity and that of anyone who might have to read your code later, avoid using nearly-identical variable names like sortedNumbers and sortedNubers. If you need to use multiple variables for the same data, make their differences more descriptive (for instance, the first one should probably be unsortedNumbers in this case).
Your mistake is in trying to treat a single string as if it were an array of numbers. You're missing two steps in there:
Parsing: Take the string that the user has typed and turn it into numbers
Formatting: Take the stored numbers and turn them back into a string to display
Lurking in that first step is the possibility that the user has not actually typed in integers. An approach that just ignores non-integer input would look like:
#IBAction func sortTextAction(_ sender: UIButton) {
guard let text = randomNumbers.text else {
finalResult.text = "" // clear out - no result on empty input
return
}
// Parse String -> [Int]:
// Split into words, then turn words into Ints,
// while discarding non-Int words
let words = text.components(separatedBy: CharacterSet.whitespacesAndNewlines)
let numbers = words
.map({ Int($0) }) // String -> Int?
.flatMap({ $0 }) // discard any nil values
let sorted = numbers.sort()
// Format [Int] -> String: glue the sorted Ints together with a space between each
finalResult.text = sorted
.map({ String(describing: $0 }) // Int -> String: turn 1 into "1"
.joined(separator: " ") // [String] -> String: turn [1, 2, 3] into "1 2 3"
}
}
Lurking behind both of these is localization: What one locale writes as "1,000" might be "1 000" or "1.000" elsewhere. For that, you'd pull in NumberFormatter to handle the conversions in a locale-aware way.

How can I check if the text of a button contains an element of an array?

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
}
}

Resources