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.
Related
Example I'm new to Swift here. I have form with rows of textfield input as shown in the picture. Is there a way to split the string in the pasteboard before using the default paste action to and paste it accordingly to the rows of input.
let pasteboard = UIPasteboard.general
let pasteboardval = pasteboard.string
_ = pasteboardval?.split(separator: "\n")
I tried splitting the string in the pasteboard but how do I make sure when user execute the default paste function it will paste it the way I want it to be.
Thousand apologies if its confusing, I'm still new here.
Here is a sample implementation
1) Create a custom textField class
class CustomTextField: UITextField {
var customPasteDelegate: PasteDelegate!
override func paste(_ sender: Any?) {
customPasteDelegate.handlePaste()
}
}
2) Create a protocol to handle paste operation
protocol PasteDelegate {
func handlePaste()
}
3) Group the uitextfields in an array and set delegate
#IBOutlet var textFields: [CustomTextField]!
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
for textField in textFields {
textField.customPasteDelegate = self
}
}
4) Implement handlePaste method in your controller
func handlePaste() {
if let pasteString = UIPasteboard.general.string {
let splitArray = pasteString.split(separator: "\n")
for (index, val) in splitArray.enumerated() {
textFieldsArray[index].text = String(val)
}
}
}
Remove each IBOutlet of textFields and add IBOutlet collection of TextFields -
#IBOutlet var txtInputFields: [UITextField]!
Now time to paste into textFields -
let pasteboard = UIPasteboard.general
let pasteboardval = pasteboard.string
let inputs = pasteboardval?.split(separator: "\n")
if let inputArray = inputs {
for i in 0..<inputArray.count {
if i < txtInputFields.count {
txtInputFields[i].text = "\(inputArray[i])"
}
}
}
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.
I am creating a custom iOS keyboard and am trying to create a function that will use a JSON dict to see what symbol to use.
Here is my function:
func switchSymbols(option: Int) {
for view in self.view.subviews {
if let button = view as? UIButton {
let buttonTag = button.tag
if (buttonTag > 0 && buttonTag < 100) {
if let text = symbolsDict?[buttonTag][option].stringValue {
print(symbolsDict)
button.setTitle(text, for: .normal)
}
}
}
}
}
And here is the factory function to create the lookup dict:
func symbolsDictFactory() -> JSON {
var dict:JSON = [:]
dict[1][0] = "1"
dict[1][1] = "["
dict[2][0] = "2"
dict[2][1] = "]"
print(dict)
return dict
}
Unfortunately, this second function produces a blank JSON array.
Little lost. Any help appreciated. Thanks in advance.
I would recommend not using JSON for data and models within your application. Your internal models should be strongly typed.
In fact, JSON is really of type [String: Any] which is not what you need since both the button tag and option values are integers. What you describe in your code is [Int: [Int: String]]. There is nothing wrong with creating a function to return your symbol lookup table. However since the table is constant, it may be simpler to just make it a property of your containing class like this.
class View: UIViewController {
private let titleForButton = [
1: [0: "1", 1: "["],
2: [0: "2", 1: "]"],
// ...
99: [0: "😊", 1: "😀"]
]
func switchSymbols(option: Int) {
for view in self.view.subviews {
if let button = view as? UIButton {
if let title = titleForButton[button.tag]?[option] {
button.setTitle(title, for: .normal)
}
}
}
}
}
Also, the bounds checking that you had for button.tag being within [1..<100] is unnecessary since the return value for the dictionary lookup is optional anyways and will not set a title for a button tag out of range.
This question already has an answer here:
Input from UITextField connected from storyboard to Swift view controller file
(1 answer)
Closed 6 years ago.
How can I take an input value from the user with a text field and then use it to perform math functions in Swift?
I want to get a value from the user and then find the sine of that value.
Plus I want to take the input and covert it into radians.
Please help.
According to your comment, you have the textfield as an IBOutlet. I've added a button to get the value:
#IBOutlet weak var textField: UITextField!
#IBOutlet weak var label: UILabel!
#IBAction func buttonPress(sender: AnyObject) {
guard let text = textField.text, value = Double(text) else { return }
label.text = String(sin(value))
}
The reason I've used guard is because if text is nil or if it's not a Double, it will just return, having done nothing (which is what I want). This way you don't have to worry about unexpected crashes when trying to calculate the value.
let sinValue = sin(Double("2")!)
is how you would process the string into a sin value
To get the text from the text field, you would need something like:
let sinValue = sin(Double(someTextField.text)!)
but you would first want to check that the text field had a value and validate that it was a number to prevent a crash.
//Initialize Textfied
var textField = UITextField(frame: CGRect(0, 0, 100, 100))
var sinNumber:Double = 0
//Now in your header (where it says class X:subclass list)
//maybe something like class Viewcontroller:UIViewController, UITextFieldDelegate
Add UITextFieldDelegate as above
Then you need to add the following function to determine when the user is done editing their TextField
func textFieldDidEndEditing(textField: UITextField) {
sinNumber = getSinOfInput(textField.text)
}
func getSinOfNumber(numbers:String) {
//If numbers is NOT a string full of numbers (it has characters), it should return nil
var num = Double(numbers)
if num != nil {
//Do login here to find the sin
num = ....
return num
}
else {
return 0
}
}
I have buttons that when pressed, will call/message a number from an array. i.e. button1 will call the number at index 0 of the array, button2 at index 1, etc.. For some reason whenever the number from the array contains a format other than xxx-xxx-xxx it crashes (i.e. (xxx) xxx-xxx). And yet, the log gives me the following error even though the array isn't nil:
Anyone know why this is happening?
Here is the code for everything:
import UIKit
import AddressBook
var contactInfo: [String] = []
[...]
override func viewDidLoad() {
super.viewDidLoad()
//this is the function that grabs the array from an app group
setUpCallMessageButtons()
[...]
callButton1.addTarget(self, action: "call:", forControlEvents: UIControlEvents.TouchUpInside)
}
func call(sender:UIButton!)
{
if (sender == callButton1) {
println("\(contactInfo)")
var url:NSURL? = NSURL(string: "tel:\(contactInfo[0])")
self.extensionContext?.openURL(url!, completionHandler:{(success: Bool) -> Void in
})
}
}
func setUpCallMessageButtons(){
let appGroupID = "**redacted**"
let defaults = NSUserDefaults(suiteName: appGroupID)
contactInfo = (defaults!.objectForKey("contactInfo") as! [String])
println("\(contactInfo)")
//This is gives the log down below. As you can see, none are nil.
}
Buttons 1,2 and 5 work while 3 and 4 always crash.
My guess is that if the phone number isn't formatted correctly, the call to convert it to an NSURL is failing and returning nil.
You probably need to wrap your call to openURL in an optional binding ("if let") block:
var url:NSURL? = NSURL(string: "tel:\(contactInfo[0])")
if let url = url
{
self.extensionContext?.openURL(url!,
completionHandler:
{
(success: Bool) -> Void in
}
}
else
{
println("Phone number \(contactInfo[0]) is not in a valid format")
}
You might want to strip away parenthesis from your phone number before trying to create your URL. A simple way would be to use the NSString method stringByReplacingOccurrencesOfString:withString:.
Here's a little storyboard - which shows you where the nil is coming from
Unexpectedly found nil means there is a variable which is expected to be non-nil but at run time was nil
This is the line of code that is causing the issue
self.extensionContext?.openURL(url!, completionHandler:{(success: Bool)
It expects url to be non-nil (i.e. the !) but it is definitely nil (see image)
If this data comes from the user or from the internet, you might want a method to strip away all non-numeric characters. Something like this (from a working playground I just banged out) :
import UIKit
func digitsOnly(#fromString: String) -> String
{
var workString = NSMutableString(string: fromString)
let digitsSet = NSCharacterSet.decimalDigitCharacterSet()
var index: Int
for index = count(fromString)-1; index>=0; index--
{
if !digitsSet.characterIsMember(workString.characterAtIndex(index))
{
workString.deleteCharactersInRange(NSRange(location:index, length:1))
}
}
return workString as String
}
let testString = "(555) 111-2222"
let result = digitsOnly(fromString:testString)
println("digitsOnly(\"\(testString)\") = \"\(result)\" ")
This displays:
digitsOnly("(555) 111-2222") = "5551112222"
Edit:
Or alternately a more Swift-like version of the same function:
func digitsOnly(#fromString: String) -> String
{
var result = String()
let digitsSet = NSCharacterSet.decimalDigitCharacterSet()
for char in fromString
{
if digitsSet.characterIsMember(char as unichar)
result += char
}
}
EDIT #2:
You can increase the set of characters that is left in place by changing the character set you use. Replace the line
let digitsSet = NSCharacterSet.decimalDigitCharacterSet()
With
let digitsSet = NSCharacterSet(charactersInString: "0123456789+-")
To preserve "+" signs and dashes. (Edit the string to include the characters you need.)