I have a UITextView
to let users type-in comments for some audio file they have just recorded.
I would like to limit the amount of the "\n" (newline characters) they can use to 5 (i.e., the comment should be up to 5 lines long).
If they try going to the sixth line I would like to show an alert with a sensible message and, upon pressing the OK button in the relative action, I would like to let the user be able to edit their text.
Delegation is already set up and implementation of the optional func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool
is what I am doing now.
The logic I put inside shows the alert correctly but then, upon clicking OK and trying to delete some characters, the method is called again and I get the alert.
I know this is due to the counter still being stuck at 5 but resetting it to 0 allows then for 9 lines or more, so it is not a solution.
Here is the code that I tried and that is not working as intended:
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
if text == characterToCheck /* \n, declared globally */ {
characterCounter += 1 // this was also declared as a global property
}
if characterCounter > 4 {
let newlineAC = UIAlertController(title: "Too many linebreaks", message: "Please go back and make your comment fit into a maximum of 5 lines", preferredStyle: .alert)
newlineAC.addAction(UIAlertAction(title: "OK", style: .default) { [weak self] (_) in
let currentText = textView.text ?? ""
guard let currentTextRange = Range(range, in: currentText) else { return }
self?.comments.text = currentText.replacingOccurrences(of: "\n", with: "@ ", range: currentTextRange)
})
present(newlineAC, animated: true)
return false
} else {
return true
}
}
No error message is thrown because the code does exactly what I ask him but I'm clearly asking it in the wrong way. What can I do?
Here is my solution:
UPDATED WITH Matt Bart feedback
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
if text == String(characterToCheck) /* \n, declared globally */ {
characterCounter += 1 // this was also declared as a global property
}
if text == "" {
let characters = Array(textView.text)
if characters.count >= range.location {
let deletedCharacter = characters[range.location]
if deletedCharacter == characterToCheck {
characterCounter -= 1
}
}
}
if characterCounter > 4 {
let newlineAC = UIAlertController(title: "Too many linebreaks", message: "Please go back and make your comment fit into a maximum of 5 lines", preferredStyle: .alert)
newlineAC.addAction(UIAlertAction(title: "OK", style: .default) { [weak self] (_) in
let currentText = textView.text ?? ""
guard let currentTextRange = Range(range, in: currentText) else { return }
self?.comments.text = currentText.replacingOccurrences(of: "\n", with: "@ ", range: currentTextRange)
})
present(newlineAC, animated: true, completion: { [weak self] in
self?.characterCounter -= 1
})
return false
} else {
return true
}
}
}
Also, declare characterToCheck
as a Character
instead of String
characterCounter
must start at 0