How to you set the maximum number of characters that can be entered into a UITextField using swift? - uitextfield

How do you limit the number of characters in a UITextField to 10, and if the user enters more than 10, only record the first 10 characters?

This solution deals with a user pasting text or tapping delete key too.
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let length = count(textField.text.utf16) + count(string.utf16) - range.length
return length <= 10
}

You can check the text before it gets displayed by implementing the UITextFieldDelegate.
class ViewController: UIViewController, UITextFieldDelegate {
textField(textField: UITextField!,
shouldChangeCharactersInRange range: NSRange,
replacementString string: String!) -> Bool {
var shouldChange = false
if countElements(textField.text) < 10 {
shouldChange = true
}
return shouldChange
}
}

Slight modification to the answer from #tugce:
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
// You can check for other things besides length here as well.
return isValidLength(textField: textField, range: range, string: string)
}
private func isValidLength(textField: UITextField, range: NSRange, string: String) -> Bool {
let length = ((textField.text ?? "").utf16).count + (string.utf16).count - range.length
return length <= 10
}
This addresses the question #Ivan asked:
what is the count method? Currently using Swift 3.
It also helps check for other conditions without crowding one method too much. For example, could do something like this to check several conditions while keeping functions a little smaller:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
return isValidKey(string: string) && isValidLength(textField: textField, range: range, string: string)
}
private func isDeleteKey(string: String) -> Bool {
if let character = string.cString(using: String.Encoding.utf8) {
let isBackSpace = strcmp(character, "\\b")
if (isBackSpace == -92) {
return true
}
}
return false
}
private func isNumericKey(string: String) -> Bool {
return string.rangeOfCharacter(from: NSCharacterSet.decimalDigits) != nil
}
private func isValidLength(textField: UITextField, range: NSRange, string: String) -> Bool {
let length = ((textField.text ?? "").utf16).count + (string.utf16).count - range.length
return length <= 10
}
private func isValidKey(string: String) -> Bool {
return isDeleteKey(string: string) || isNumericKey(string: string)
}
I'll also mention that to utilize textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool you'll need to conform to the UITextFieldDelegate and set the delegate of the text field. e.g.:
class MyClass: UITextFieldDelegate {
#IBOutlet weak var textField: UITextField!
init() {
textField.delegate = self
}
}

Related

How to use bit instead of bool in golang structure?

type EventPrefs struct {
Call bool
Presence bool
Endpoint bool
VoiceMail bool
CallRecording bool
}
Currently, the size of that struct type is 5 bytes but I would like to use bits. Is there any way to do that?
There is no "bit" type in Go, so if you want to pack multiple bool information into bits, you have to implement it yourself. Declare a field of type uint8 (or uint16 or any other integer type), and provide methods that get / set specific bits of the field.
General bit setting / clearing is as simple as this:
var masks = []uint8{0x01, 0x02, 0x04, 0x08, 0x10}
func set(field, data uint8, b bool) uint8 {
if b {
return data | masks[field] // Set bit
}
return data ^ masks[field] // Clear bit
}
func get(field, data uint8) bool {
return data&masks[field] != 0
}
Packing your 5 bool fields into an uint8 value:
type EventPrefs struct {
data uint8
}
func (e *EventPrefs) SetCall(b bool) { e.data = set(0, e.data, b) }
func (e *EventPrefs) Call() bool { return get(0, e.data) }
func (e *EventPrefs) SetPresence(b bool) { e.data = set(1, e.data, b) }
func (e *EventPrefs) Presence() bool { return get(1, e.data) }
func (e *EventPrefs) SetEndpoint(b bool) { e.data = set(2, e.data, b) }
func (e *EventPrefs) Endpoint() bool { return get(2, e.data) }
func (e *EventPrefs) SetVoiceMail(b bool) { e.data = set(3, e.data, b) }
func (e *EventPrefs) VoiceMail() bool { return get(3, e.data) }
func (e *EventPrefs) SetCallRecording(b bool) { e.data = set(4, e.data, b) }
func (e *EventPrefs) CallRecording() bool { return get(4, e.data) }
Testing it:
ep := &EventPrefs{}
fmt.Println("Calls:", ep.Call(), ep.data)
ep.SetCall(true)
fmt.Println("Calls:", ep.Call(), ep.data)
fmt.Println("Presence:", ep.Presence(), ep.data)
ep.SetPresence(true)
fmt.Println("Presence:", ep.Presence(), ep.data)
ep.SetPresence(false)
fmt.Println("Presence:", ep.Presence(), ep.data)
Which outputs (try it on the Go Playground):
Calls: false 0
Calls: true 1
Presence: false 1
Presence: true 3
Presence: false 1
Is saving 4 bytes worth the hassle? Rarely.
Note: the above solution can have many variations. For example the masks can be "computed" using bitshifts, the set() and get() functions could be methods of EventPrefs and so the data parameter would not be needed (and set() could directly set the EventPrefs.data field so no return value would be needed either). If set() remains a function, the data param could be a pointer so set() could change the pointed value without returning the new data etc. The data field may have its own declared type e.g. bitpack with get() and set() methods attached to it.
See related: Difference between some operators "|", "^", "&", "&^". Golang

to look at the suffix of the text of the text field

I want to let the people login to the certain domain, but it always shows a error.
Cannot convert value of type 'String' to expected argument type 'Int').
how can I deal with it?
import UIKit
import FirebaseAuth
class ViewController: UIViewController {
#IBOutlet var emailTextField: UITextField!
#IBOutlet var passwordTextField: UITextField!
#IBAction func signUp(_ sender: Any) {
Auth.auth().createUser(withEmail: emailTextField.text!, password: passwordTextField.text!) { (result, error) in
if error != nil{
print(error)
}else{
self.performSegue(withIdentifier: "createdUser", sender: self)
}
}
}
#IBAction func signIn(_ sender: Any) {
Auth.auth().signIn(withEmail: emailTextField.text!, password: passwordTextField.text!) { (result, error) in
if error != nil{
print(error)
}else{
var hi = self.emailTextField.text
if hi?.suffix("#hkugac.edu.hk"){ //error here
self.performSegue(withIdentifier: "logged", sender: self)
}
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
Try using the hasSuffix method. https://developer.apple.com/documentation/swift/string/1541149-hassuffix
var hi = self.emailTextField.text
if let mail = hi, mail.haSuffix("#hkugac.edu.hk")
{
self.performSegue(withIdentifier: "logged", sender: self)
}
else
{
// Dome some error handling here.
}
Also, I think it would be better to check the mail before you call the signIn function.

Can't set default value UIPicker swift 2

I have a swift project with a custom cell from a tableview, ans inside it I have a label to display the value of a UIPicker. The UiPicker appear in the keyboard when you press the label, I wan't to be able to set default values to my UIPicker, I tried a lot of differents technics with the 2 methods :
selectRow(), without success, here is my CustomCell code :
import UIKit
class CustomCell: UITableViewCell, UIPickerViewDataSource, UIPickerViewDelegate {
#IBOutlet weak var answer: UITextField!
var delegate: QuestionSelectorCellDelegate?
var pickOption: [String] = []
var pickerView:UIPickerView = UIPickerView()
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
#IBAction func editBeginQuestionSelectorCell(sender: UITextField) {
pickerView = UIPickerView()
pickerView.delegate = self
sender.inputView = pickerView
}
func displayBlock(block: Block){
if block.answers != nil {
pickOption = block.answers! // block.answers! = ["blue","red","green"] for example
}
}
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return pickOption.count
}
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return pickOption[row]
}
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if row < pickOption.count {
answer.text = pickOption[row]
delegate?.updateQuestionSelectorCell(self, rep: pickOption[row])
}
}
}
Updated your code.
You didn't set the pickerView.dataSource!
If i understood your question, you want an element to be selected by default, other than element at index 0.
I also added that.
import UIKit
class CustomCell: UITableViewCell, UIPickerViewDataSource, UIPickerViewDelegate {
#IBOutlet weak var answer: UITextField!
var delegate: QuestionSelectorCellDelegate?
var pickOption: [String] = []
var pickerView:UIPickerView = UIPickerView()
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
#IBAction func editBeginQuestionSelectorCell(sender: UITextField) {
pickerView = UIPickerView()
pickerView.delegate = self
// --- Thats what I added ---
pickerView.dataSource = self
let indexOfDefaultElement = 1 // Make sure that an element at this index exists
pickerView.selectRow(indexOfDefaultElement, inComponent: 0, animated: false)
sender.inputView = pickerView
}
func displayBlock(block: Block){
if block.answers != nil {
pickOption = block.answers! // block.answers! = ["blue","red","green"] for example
}
}
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return pickOption.count
}
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return pickOption[row]
}
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if row < pickOption.count {
answer.text = pickOption[row]
delegate?.updateQuestionSelectorCell(self, rep: pickOption[row])
}
}
}

'(String) -> String' is not convertible to 'SQLHandler'

The line below, at SQLHandler.translateQuery("Do mysql stuff"), is throwing the error: '(String) -> String' is not convertible to 'SQLHandler'. Why is it doing this? Thank you in advance.
Code 1 (Used wherever and whenever needed)
var query: String = "mysql stuff"
SQLHandler.sendQuery(SQLHandler.translateQuery("domain and \(query)"))
Code 2, SQLHandler.swift (Called whenever needed)
import Foundation
class SQLHandler {
func translateQuery(queryToTranslate: String) -> String{
println(queryToTranslate)
return queryToTranslate.stringByReplacingOccurrencesOfString(" ", withString: "_", options: NSStringCompareOptions.LiteralSearch, range: nil)
}
func sendQuery(query: String){
println(query)
let url = NSURL(string: "url and query goes here")
let task = NSURLSession.sharedSession().dataTaskWithURL(url!, completionHandler: { (data, response, error) -> Void in })
task.resume()
}
}
You are calling an instance method on the class itself.
Either create an instance and call the method:
var sqlHandler = SQLHandler()
sqlHandler.translateQuery("domain and \(query)")
or define the methods as class methods :
class func translateQuery(queryToTranslate: String) -> String ...
class func sendQuery(query: String) ...

Custom NSFormatter returning nil in swift

I have an NSFormatter in Swift, which is attached to an NSTextField. It prevents illegal characters from being entered, but when I try to access the value of the next field it gives a nil value.
Below is the class:
class PSEntryNameFormatter : NSFormatter {
override func stringForObjectValue(obj: AnyObject?) -> String? {
if obj == nil {
println("stringForObjectValue: obj is nil, returning nil")
return nil
}
if let o = obj as? String {
println("stringForObjectValue: obj is string, returning \(o)")
return o
}
println("stringForObjectValue: obj is not string, returning nil")
return nil
}
override func getObjectValue(obj: AutoreleasingUnsafeMutablePointer<AnyObject?>, forString string: String, errorDescription error: AutoreleasingUnsafeMutablePointer<NSString?>) -> Bool {
println("getObjectValue: \(string)")
let obj = string
return true
}
override func isPartialStringValid(partialString: String?, newEditingString newString: AutoreleasingUnsafeMutablePointer<NSString?>, errorDescription error: AutoreleasingUnsafeMutablePointer<NSString?>) -> Bool {
if let s = partialString {
var illegals : String = join("",s.componentsSeparatedByCharactersInSet(PSEntryNameFormatterCharacterSet))
var goods = s.componentsSeparatedByCharactersInSet(NSCharacterSet(charactersInString: illegals))
let newString : NSString = join("", goods)
if String(newString) == s {
println("isPartialStringValid: partial string ok")
return true
}
}
println("isPartialStringValid: partial string bad")
return false
}
}
And here is how I try to access:
func control(control: NSControl, textShouldEndEditing fieldEditor: NSText) -> Bool {
println("Text should end editing")
if (control == nameTextField) {
var name = nameTextField.objectValue as String
setObjectName(name)
}
return true
}
For debugging I add the println statements, and here is what happens when the textfield is set to 'Template' and then I delete two characters:
stringForObjectValue: obj is string, returning Template
stringForObjectValue: obj is string, returning Template
isPartialStringValid: partial string ok
getObjectValue: Templat
isPartialStringValid: partial string ok
getObjectValue: Templa
Then I press enter:
getObjectValue: Templa
Text should end editing
getObjectValue: Templa
stringForObjectValue: obj is nil, returning nil
getObjectValue:
stringForObjectValue: obj is nil, returning nil
stringForObjectValue: obj is nil, returning nil
fatal error: unexpectedly found nil while unwrapping an Optional value
And then it crashes on the line when I cast to string. Obviously I can prevent the crash, but first I want to find out why it is returning nil. Any help very much appreciated!
The problem is in your getObjectValue function.
You should be assigning the value in this manner:
obj.memory = string
instead of
let obj = string
I have a similar problem and got a partial fix:
override func stringForObjectValue(obj: AnyObject) -> String? {
if let desc = obj.description {
println("sFO=\(obj)")
} else {
println("sFO=nil")
}
return obj.description
}
But each time I tab out of the field its contents is set to nil again. Still stuck with that. I had no issue with the analog OC code.

Resources