How to get length of text enter in search bar? - swift

I want to get the length of the text that is entered in a UISearchBar
I use the function that is called when the the searcbbar text starts editing.
func searchBarTextDidBeginEditing(searchBar: UISearchBar!) {
println("EDITING")
//TODO: Get length of text entered in searchBar
}
This doesn't work:
func searchBarTextDidBeginEditing(searchBar: UISearchBar!) {
println("EDITING")
//TODO: Get length of text entered in searchBar
//Doesn't work. Error: String doesn't have a member named length
searchBar.text.length
}
How can i retrieve the length of the entered text?
Ended up doing this:
searchBar.text.bridgeToObjectiveC().length

The problem is simply that the text property, like most objects arriving from the Cocoa API, might be nil. You have to assure Swift that it is not. Like this:
let len = countElements(searchBar.text!)

Related

Build Recursive Text View in SwiftUI

My goal is to create a SwiftUI view that takes a String and automatically formats that text into Text views. The portion of the string that needs formatting is found using regex and then returned as a Range<String.Index>. This can be used to reconstruct the String once the formatting has been applied to the appropriate Text views. Since there could be multiple instances of text that needs to be formatted, running the formatting function should be done recursively.
struct AttributedText: View {
#State var text: String
var body: some View {
AttributedTextView(text: text)
}
#ViewBuilder
private func AttributedTextView(text: String) -> some View {
if let range = text.range(of: "[0-9]+d[0-9]+", options: .regularExpression) {
//The unattributed text
Text(text[text.startIndex..<range.lowerBound]) +
//Append the attributed text
Text(text[range]).bold() +
//Search for additional instances of text that needs attribution
AttributedTextView(text: String(text[range.upperBound..<text.endIndex]))
} else {
//If the searched text is not found, add the rest of the string to the end
Text(text)
}
}
I get an error Cannot convert value of type 'some View' to expected argument type 'Text', with the recommended fix being to update the recursive line to AttributedTextView(text: String(text[range.upperBound..<text.endIndex])) as! Text. I apply this fix, but still see the same compiler error with the same suggested fix.
A few workarounds that I've tried:
Changing the return type from some View to Text. This creates a different error Cannot convert value of type '_ConditionalContent<Text, Text>' to specified type 'Text'. I didn't really explore this further, as it does make sense that the return value is reliant on that conditional.
Returning a Group rather than a Text, which causes additional errors throughout the SwiftUI file
Neither of these solutions feel very "Swifty". What is another way to go about this? Am I misunderstanding something in SwiftUI?
There are a few things to clarify here:
The + overload of Text only works between Texts which is why it's saying it cannot convert some View (your return type) to Text. Text + Text == Text, Text + some View == ☠️
Changing the return type to Text doesn't work for you because you're using #ViewBuilder, remove #ViewBuilder and it'll work fine.
Why? #ViewBuilder allows SwiftUI to defer evaluation of the closure until later but ensures it'll result in a specific view type (not AnyView). In the case where your closure returns either a Text or an Image this is handy but in your case where it always results in Text there's no need, #ViewBuilder forces the return type to be ConditionalContent<Text, Text> so that it could have different types.
Here's what should work:
private static func attributedTextView(text: String) -> Text {
if let range = text.range(of: "[0-9]+d[0-9]+", options: .regularExpression) {
//The unattributed text
return Text(text[text.startIndex..<range.lowerBound]) +
//Append the attributed text
Text(text[range]).bold() +
//Search for additional instances of text that needs attribution
AttributedTextView(text: String(text[range.upperBound..<text.endIndex]))
} else {
//If the searched text is not found, add the rest of the string to the end
return Text(text)
}
}
I made it static too because there's no state here it's a pure function and lowercased it so it was clear it was a function not a type (the function name looks like a View type).
You'd just call it Self.attributedTextView(text: ...)

Swift - check if attributed text is empty

I have a UITextField on which I set a current value as attributed text as follows:
public var currentValue: NSAttributedString {
get {
return inputField.attributedText ?? NSAttributedString()
}
set {
inputField.attributedText = newValue
}
}
This was previously just a String but I now need to add formatting to parts of the text.
However, I have a method I need to pass on these fields which begins with the condition to see if the field is empty. Previously I started this with:
if textField.currentValue.isEmpty {
// Perform logic
}
However, obviously NSAttributedText has no isEmpty member. How can I perform the same check on NSAttributedText?
NSAttributedText has no isEmpty property but it has one called length. You can simply check if it is equal to zero:
if currentValue.length == .zero {
// Perform logic
}
There's also attributedText.string.isEmpty

How to use observable object in wrapped textfield class

So I have 4 textfields with lines underneath them all. When the user enters a number into the first textfield it jumps to the next and so on until a number it entered into the last field at that point the keyboard will just resign and the pin will be evaluated. I want to be able to change the color of the lines depending on which textfield is focused the time.
What I have tried
So far I've tried making an instance of an observable object in a representable swift file that makes up my textfield. So I'll change the Observable Object when nextField becomes first responder and I'll change a state variable in my SwiftUI file. When I try to make an instance of my Observable Object in my representable file I get an error that states "Class 'SchoolCode_WrappableTextField' has no initializers". Overall I'm essentially just trying to change the color of the underline depending on which textfield is focused at the time. Any help is appreciated, thanks.
#objc func textChanged(sender: UITextField) {
if (sender.text?.count)! > 0 {
if let nextField = sender.superview?.superview?.viewWithTag(sender.tag + 1) as? UITextField{
nextField.becomeFirstResponder()
}else{
sender.resignFirstResponder()
}
}
}`
UI

Swift 2.2: Optional Binding in a function

Heys guys,
I am pretty new into programming and therefore I've followed I course on Udemy to teach me Swift 2.2.
For learning purpose I have been trying to program a BMI-calculator where I have a textfield (which just displays the value) and a slider where I can put my weight in kg. After dragging the slider the value is visible in the textfield. I cannot put a value into the textfield so that it is displayed on the slider!
The same textfield-slider relation is used with the height in cm. Now I created an IBAction the bring my kgSlider.value into my kgField.text and it looks like this:
#IBAction func kgSet(sender: AnyObject) {
kgField.text! = String(Int(kgSlider.value))
}
Thats works fine but I unwrapped (like the teacher in the course) without knowing, if there really is a value. Okay, I know in this case that there will be a value, but I would like to go more real and therefore I tried to use an Optional-Binding to find out, if there is a value instead of directly unwrap it.
Therefore I used the cm.Field and the cm.Slider in my code but it doesn't work for now and I don't know why. The code is the following:
#IBAction func cmSet(sender: AnyObject) {
if let tempCm = String(Int(cmSlider.value)) as String! {
cmField.text = tempCm
}
}
So I created the constant called tempCM which will got the value from the cmSlider, if there is a value. Therefore I casted the cmSlider.value like in the other IBAction into an Int and then into a String. If there is the value it will carry it into the cmField.text. This didn't work, therefore I tried to use the "as String!" statement but know I get always 0 instead of the correct value.
So what am I doing wrong there?
So, this should compile fine and provide you with your desired result.
#IBAction func cmSet(sender: AnyObject) {
if let tempCm = String(Int(cmSlider.value)) {
cmField.text = tempCm
}
}
You could also try this
cmField.text = String(Int(cmSlider.value)) ?? " "
in the second example, you are using the optional operator to say if you can convert this to an Int then that Int to a string set the cmField.text property to its value, otherwise use a blank space as the default value.

How do you add the content of two textfields?

In my app I have got two textfields, one label and one button. I managed to get the content of the one textfield to be displayed in the label, but I want to display the content of both of the textfields.
#IBAction func buttonPushed(sender: UIButton) {
Label.text = "\(textfield1.text)"
+ "\(textfield2.text)"
The code above is the closest I´ve come, but the Label displays:
Optional"whatever I typed in the textfield"Optional"whatever I typed
in the textfield"
You have to unwrap the text
Label.text = textfield1.text! + textfield2.text!
You are concatenating strings, not adding numbers. In order to add the values, you need to cast the textfield value to a number like:
field.text!.toInt()
the ! unwraps the value to remove the "Optional". and toInt() casts a string (text) to and integer.
In the end, you code will look something like this:
#IBAction func buttonPushed(sender: UIButton) {
Label.text = "\(textfield1.text!.toInt())"
+ "\(textfield2.text!.toInt())"