How to set delegate of UITextField in separate class in Swift? - swift

I'm trying to implement UITextFieldDelegate in separate class, but it didn't working:
class ViewController: UIViewController {
#IBOutlet var TextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
let restrictor = TextFieldRestrictController()
TextField.delegate = restrictor
}
}
class TextFieldRestrictController : NSObject, UITextFieldDelegate {
public func textField(_ textField: UITextField,
shouldChangeCharactersIn range: NSRange,
replacementString string: String) -> Bool {
let inverseSet = NSCharacterSet(
charactersIn:"0123456789.").inverted
let components = string.components(separatedBy: inverseSet)
let filtered = components.joined(separator:"")
return string == filtered
}
}
But this is working:
class ViewController: UIViewController {
#IBOutlet var TextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
TextField.delegate = self
}
public func textField(_ textField: UITextField,
shouldChangeCharactersIn range: NSRange,
replacementString string: String) -> Bool {
let inverseSet = NSCharacterSet(
charactersIn:"0123456789.").inverted
let components = string.components(separatedBy: inverseSet)
let filtered = components.joined(separator:"")
return string == filtered
}
}
Is there something wrong?

UITextField's .delegate is a weak property so at the end of viewDidLoad method,
restrictor will be deallocated because there is no other strong reference around that is pointing to the object which it points to.
You can try printing out ValidationTextField.delegate in viewDidAppear(animated:) and see it returns nil.
To overcome this problem, you can define restrictor as an instance variable so it'll stay alive as long as the view controller is alive:
class ViewController: UIViewController {
#IBOutlet weak var ValidationTextField: UITextField!
let restrictor = TextFieldRestrictController()
override func viewDidLoad() {
super.viewDidLoad()
ValidationTextField.delegate = restrictor
}
}

Related

How to only enable button when two text fields are not empty - Swift + storyboard

Recently, I am writing my own project with swift.
I use storyboard and create two text fields and one button.
How do I enable the button only when two text fields are not empty?
Here is what I had so far
#IBAction func enableNextBtn(_ sender: UITextField) {
if !sender.text!.isEmpty {
nextBtn.isEnabled = true
} else {
nextBtn.isEnabled = false
}
}
1 You need one IBOutlet for each TextField:
#IBOutlet var textField1: UITextField!
#IBOutlet var textField2: UITextField!
2 DonĀ“t forget to conform to UITextFieldDelegate like in:
MyViewController: UITextFieldDelegate{}
3 In viewDidLoad set self as UITextFieldDelegate for your TextFields:
textField1.delegate = self
textField2.delegate = self
4 implemente the following method which is called with every keystroke:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
nextBtn.isEnabled = !textField1.text?.isEmpty && !textField2.text?.isEmpty
return true
}
Hope this approach helps.

How can I disable this done button until these two text fields have values?

My goal is for the done button to be disabled while both of these text fields are empty. I have the logic for the top button, but as soon the top text field "taskNameTextFIeld" has at least one character, the done button is enabled. I don't want users to be able to press done while "timeTextField" is empty. You can see what I have so far in textField().
import UIKit
protocol AddNewTaskViewControllerDelegate: class {
func addNewTaskViewControllerDidCancel(_ controller: AddNewTaskViewController)
func addNewTaskViewController(_ controller: AddNewTaskViewController,
didFinishAdding item: TaskData)
}
class AddNewTaskViewController: UITableViewController, UITextFieldDelegate {
#IBOutlet weak var taskNameTextFIeld: UITextField!
#IBOutlet weak var timeTextFIeld: UITextField!
#IBOutlet weak var doneBarButton: UIBarButtonItem!
weak var delegate: AddNewTaskViewControllerDelegate?
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let oldText = textField.text! as NSString
let newText = oldText.replacingCharacters(in: range, with: string) as NSString
doneBarButton.isEnabled = newText.length > 0
return true
}
#IBAction func cancel(_ sender: Any) {
delegate?.addNewTaskViewControllerDidCancel(self)
}
#IBAction func done(_ sender: Any) {
let item = TaskData()
item.task = taskNameTextFIeld.text!
item.time = timeTextFIeld.text!
delegate?.addNewTaskViewController(self, didFinishAdding: item)
}
func textFieldShouldReturn(_ TextField: UITextField) -> Bool {
self.view.endEditing(true)
return false
}
override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
return nil
}
override func viewDidLoad() {
super.viewDidLoad()
self.taskNameTextFIeld.delegate = self;
self.timeTextFIeld.delegate = self;
// Do any additional setup after loading the view.
}
}
The issue is you aren't checking both fields. Change:
doneBarButton.isEnabled = newText.length > 0
To an actual check of things:
if taskNameTextFIeld.text.length > 0 && timeTextFIeld.text.length > 0 {
doneBarButton.isEnabled = newText.length > 0
}
Also, I'd recommend changing the names of both text fields to be Field and not Field.
Here is some detail on how I solved the problem. Text fields themselves did not have a length member so I compared character count instead.
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let oldText = textField.text! as NSString
let newText = oldText.replacingCharacters(in: range, with: string) as NSString
//doneBarButton.isEnabled = newText.length > 0
if (taskNameTextFIeld.text?.characters.count)! > 0 && (timeTextFIeld.text?.characters.count)! > 0 {
doneBarButton.isEnabled = newText.length > 0
}
return true
}

Converting UITextField to String in Swift

I'm trying to convert a UITextField object to a String so that I can pass it to a function in my model file. But it is printing a blank even after I type in some characters in the name input text field and then click outside of it. Why is nothing stored there?
In view controller file:
#IBOutlet weak var nameInputText: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
nameInputText.delegate = self
let text: String = nameInputText.text!
print(text) //this prints a blank
model.validateName(nametext: text)
}
It should be like below
#IBOutlet weak var usernameInputText : UITextField!
override func viewDidLoad() {
super.viewDidLoad()
usernameInputText.delegate = self
}
func ClickOnButton()
{
let text: String = usernameInputText.text!
print(text) //this prints My text
model.validateName(nametext: text)
}
func textField(_ textField: UITextField,
shouldChangeCharactersIn range: NSRange,
replacementString string: String)
-> Bool
{
let text: String = usernameInputText.text!
print(text) //this prints My text
model.validateName(nametext: text)
}
viewDidLoad gets called before your ViewController would be visible to the user, so any text field can only contain text if you have set that text before (in InterfaceBuilder or code). If you want to access user input from that text field, you should either do that in textFieldDidEndEditing or in any other function which you know can only be called after the user interaction happened.
#IBOutlet weak var nameInputText: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
nameInputText.delegate = self
}
extension ViewController: UITextFieldDelegate {
func textFieldDidEndEditing(_ textField: UITextField) {
model.validateName(nametext: textField.text)
}
}

the button is disabled when text view is empty else is enabled

I'm developing note app, when the text view is empty the done button should be disabled so user could not be able to save empty notes into data base, else the button should be enabled.
here's my code below, my attempts have failed; how I can solve this problem?
#IBOutlet weak var textView: UITextView!
#IBOutlet weak var done: UIBarButtonItem!
override func viewDidLoad() {
super.viewDidLoad()
title = note?.text
if (self.textView.text.isEmpty){
done.enabled = false
}
if let noteContent = note
{
textView.text = noteContent.text
}
self.navigationController!.toolbarHidden = false;
}
func textViewShouldBeginEditing(textView: UITextView) -> Bool{
done.enabled = true
return done.enabled
}
Make your view controller conform to UITextViewDelegate protocol
In Interface Builder, connect the delegate on the text view to your view controller.
Add the following function to your view controller:
func textViewDidChange(textView: UITextView) {
if textView == self.textView {
self.doneButton.enabled = !textView.text.isEmpty
}
}
Try to use another delegate method for you're purpose. This is example :
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var button: UIButton!
#IBOutlet weak var textView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
textView.delegate = self
if (textView.text.isEmpty) {
button.enabled = false
}
}
}
extension ViewController: UITextViewDelegate {
func textView(textView: UITextView, range: NSRange, replacementText text: String) -> Bool
{
if (!textView.text.isEmpty) {
button.enabled = true
} else {
button.enabled = false
}
return true
}
}
Try this in textViewDidChange method:
yourBarButtonItem.isEnabled = !(yourTextField.text?.isEmpty ?? false)

Swift: Button Enabling Not Working?

I have a button that is disabled in my view controller. I have IBActions for when two text fields are edited. I am trying to enable the button when two text fields both contain integers. I have tried to do this, but whenever I run the ios simulator, the button stays disabled even when I put integers into each text field. Why is it staying disabled? I am new to swift, so please help me out. Here is the code for my entire project:
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var calculatorButton: UIButton!
#IBOutlet weak var inspirationLabel: UILabel!
#IBOutlet weak var beginningLabel: UILabel!
#IBOutlet weak var calculatorContainer: UIView!
#IBOutlet weak var answer1Label: UILabel!
#IBOutlet weak var doneButton: UIButton!
#IBOutlet weak var yourWeightTextField: UITextField!
#IBOutlet weak var calorieNumberTextField: UITextField!
#IBOutlet weak var menuExampleButton: UIButton!
#IBOutlet weak var aboutButton: UIButton!
#IBOutlet weak var calculateButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib
yourWeightTextField.delegate = self
calorieNumberTextField.delegate = self
calculateButton.enabled = false
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func calculatorButtonTapped(sender: AnyObject) {
calculatorContainer.hidden = false
inspirationLabel.hidden = true
beginningLabel.hidden = true
menuExampleButton.hidden = true
aboutButton.hidden = true
}
#IBAction func yourWeightEditingDidEnd(sender: AnyObject) {
yourWeightTextField.resignFirstResponder()
}
#IBAction func calorieNumberEditingDidEnd(sender: AnyObject) {
calorieNumberTextField.resignFirstResponder()
}
var yourWeightFilled = false
var calorieNumberFilled = false
func yourWeightTextFieldValueValidInt(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
// Find out what the text field will be after adding the current edit
let text = (yourWeightTextField.text as NSString).stringByReplacingCharactersInRange(range, withString: string)
if let intVal = text.toInt() {
self.yourWeightFilled = true
} else {
self.yourWeightFilled = false
}
return true
}
func calorieNumberTextFieldValueValidInt(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
// Find out what the text field will be after adding the current edit
let text = (calorieNumberTextField.text as NSString).stringByReplacingCharactersInRange(range, withString: string)
if let intVal = text.toInt() {
self.calorieNumberFilled = true
} else {
self.calorieNumberFilled = false
}
return true
}
#IBAction func yourWeightTextFieldEdited(sender: AnyObject) {
if self.yourWeightFilled && self.calorieNumberFilled {
self.calculateButton.enabled = true
}
}
#IBAction func calorieNumberTextFieldEdited(sender: AnyObject) {
if self.yourWeightFilled && self.calorieNumberFilled {
self.calculateButton.enabled = true
}
}
}
Your delegate methods are a bit mixed up -- they have to be named exactly what the caller expects, or they won't be found, so yourWeightTextFieldValueValidInt() and calorieNumberTextFieldValueValidInt() aren't being called at all. Instead you'll need to handle the edits to both text fields in a single method:
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
// Find out what the text field will be after adding the current edit
let text = (textField.text as NSString).stringByReplacingCharactersInRange(range, withString: string)
if textField == yourWeightTextField {
yourWeightFilled = text.toInt() != nil
} else if textField == calorieNumberTextField {
calorieNumberFilled = text.toInt() != nil
}
return true
}