manage invite manage invite - 9 days ago 6
iOS Question

UITextField delegate method not called

I am presenting an alert with UITextfield, but its delegate methods are not getting called. What wrong I might be doing. I am using the below code to show the alert with textfield.

func takePasscodeToEnableTouch(){
self.passcodeInputOperationType = .EnableTouchID

alertControllerPassCodeEntry = UIAlertController(title: "", message: "Enter Passcode to enable the Touch Id.", preferredStyle: UIAlertControllerStyle.Alert)

let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel) { (action) -> Void in
}
alertControllerPassCodeEntry!.addAction(cancelAction)

alertControllerPassCodeEntry!.addTextFieldWithConfigurationHandler { (txtField) -> Void in
txtField.placeholder = "Enter passcode"
txtField.delegate = self
txtField.tag = TextFieldTag.EnterPassCode
txtField.keyboardType = UIKeyboardType.NumbersAndPunctuation
txtField.accessibilityIdentifier = "PassCode"
txtField.secureTextEntry = true
txtField.addTarget(self, action:"textFieldDidChange:", forControlEvents: UIControlEvents.EditingChanged)
}

let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegate.window?.rootViewController?.presentViewController(alertControllerPassCodeEntry!, animated: true, completion: nil )
}


And the textField delegate methods are :

func textFieldShouldBeginEditing(textField: UITextField) -> Bool
{
return true
}

func textFieldDidBeginEditing(textField: UITextField) // became first responder
{

}

func textFieldShouldEndEditing(textField: UITextField) -> Bool
{
return true
}

func textFieldDidEndEditing(textField: UITextField)
{

}

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
{
var isLimitExist: Bool
var accessIndentifier: String
if let str = textField.accessibilityIdentifier
{
accessIndentifier = str
}
else
{
accessIndentifier = ""
}

//checkFieldLimit function is used to check the limit of text and restrict
isLimitExist = UIUtils.checkFieldLimit(accessIndentifier, stringToMatch: textField.text!, rangeLength: range.length, stringLength: string.characters.count)

if !isLimitExist
{
return false
}
return true
}

Answer

Ok, so with information from the comments, everything seems clear now. To recap, you call the method showing the alert like this :

@IBAction func swtchTouchAction(sender: UISwitch) { 
    if sender.on { 
        let passCodeManager = PasscodeManager() 
        passCodeManager.delegate = self 
        passCodeManager.takePasscodeToEnableTouch() 
    } else { 
        let passCodeManager = PasscodeManager() 
        passCodeManager.delegate = self
        passCodeManager.authenticatePasscodeToDisalbeTouch() 
    } 
}

Now, you don't retain (meaning - assign to a strong property) the passCodeManager anywhere in here. This means, that at the end of this method this object gets destroyed (thanks to ARC - Automatic Reference Counting). One may think that it would get retained because you assigned it as a delegate of the text field, but delegates are weak proeprties 99.99% of time - this means that they don't bump the retain count of objects assigned to them.

To solve your immediate issue you should make a property in your class in which you have swtchTouchAction method and change your code like this :

var passCodeManager: PasscodeManager?

@IBAction func swtchTouchAction(sender: UISwitch) { 
    if sender.on { 
        self.passCodeManager = PasscodeManager() 
        self.passCodeManager?.delegate = self 
        self.passCodeManager?.takePasscodeToEnableTouch() 
    } else { 
        self.passCodeManager = PasscodeManager() 
        self.passCodeManager?.delegate = self
        self.passCodeManager?.authenticatePasscodeToDisalbeTouch() 
    } 
}

This will be enough to retain your passcode manager.

I'd also suggest you read up on how memory management is done in Swift.