Swift why strcmp of backspace returns -92?
Let's analyze a little bit the code and the data that flows through that code:
string
is an empty string, as when you delete a character, the textfield tries to replace it by "nothing" (an empty string)- due to #1,
char
holds only the string terminator, which is\0
, in memory:[0]
- "\\b" translates to the
\b
string, in memory:[92, 98]
- due to #2 and #3,
strcmp
returns 0 - 92 => -92.
Not sure why people use this "algorithm", when they could simply check for the emptiness of the string
parameter. I assume they firstly tried to use the \b
escape sequence, which doesn't seem to be a valid one, so they added an extra \
character, which compiled, but resulted in an incorrect escape sequence, as \\
is the escaping sequence for the backslash character, resulting in the b
part being represented as the plain letter.
Seems that backspace is not reported by the delegate method, instead the delegate method is asked to operate on strings. Detecting the actual key press might need some UIEvent
/RunLoop
hooks.
Note that an empty string passed to textField(_,shouldChangeCharactersIn:,replacementString:)
doesn't always mean that backspace was presset, a cut operation might result too in an empty string being sent to the delegate. You could try and check the range and assume that for a range of 1 backspace was pressed, however the user can also cut one character...
Completely disable 'backspace' being pressed Swift
You need to simply implement textView(_:shouldChangeTextIn:replacementText:)
and check for empty
replacementText
.
Empty replacementText == backspace pressed
If the text
is Empty
1return false. Else
return true`.
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
if text.isEmpty {
return false
}
return true
}
Detect backspace Event in UITextField
Swift 4.2
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
if let char = string.cString(using: String.Encoding.utf8) {
let isBackSpace = strcmp(char, "\\b")
if (isBackSpace == -92) {
print("Backspace was pressed")
}
}
return true
}
Older Swift version
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let char = string.cStringUsingEncoding(NSUTF8StringEncoding)!
let isBackSpace = strcmp(char, "\\b")
if (isBackSpace == -92) {
println("Backspace was pressed")
}
return true
}
Secure TextField clears whole text, on clearing single character using backspace
You need to detect backspace
tapped and then remove last element from string with using textField
delegate
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let char = string.cString(using: String.Encoding.utf8)!
let isBackSpace = strcmp(char, "\\b")
if (isBackSpace == -92) {
print("Backspace pressed")
}
return true
}
Dont forget to add UITextFieldDelegate to your ViewController
Allow Backspace with character set
When the user taps the backspace, string
will be the empty string. So rangeOfCharacter
will be nil
so your code returns false
preventing the backspace from working.
Try this:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
return string.isEmpty || string.rangeOfCharacter(from: CharacterSet.letter) != nil
}
textfield backspace action identify when textfield is empty?
followed by @Marmik Shah and @Prashant Tukadiya answer here I add my answer , for quick answer I taken the some code from here
step 1 :
create the IBOutletCollection for your all textfields as well as don't forget to set the tag in all textfields in the sequence order, for e.g [1,2,3,4,5,6]
class ViewController: UIViewController{
@IBOutlet var OTPTxtFields: [MyTextField]! // as well as set the tag for textfield in the sequence order
override func viewDidLoad() {
super.viewDidLoad()
//change button color and other options
OTPTxtFields.forEach { $0.textColor = .red; $0.backspaceTextFieldDelegate = self }
OTPTxtFields.first.becomeFirstResponder()
}
step 2 :
in your current page UITextField delegate method
extension ViewController : UITextFieldDelegate, MyTextFieldDelegate {
func textFieldDidEnterBackspace(_ textField: MyTextField) {
guard let index = OTPTxtFields.index(of: textField) else {
return
}
if index > 0 {
OTPTxtFields[index - 1].becomeFirstResponder()
} else {
view.endEditing(true)
}
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let newString = ((textField.text)! as NSString).replacingCharacters(in: range, with: string)
if newString.count < 2 && !newString.isEmpty {
textFieldShouldReturnSingle(textField, newString : newString)
// return false
}
return newString.count < 2 || string == ""
//return true
}
override public func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
if action == #selector(copy(_:)) || action == #selector(paste(_:)) {
return false
}
return true
}
func textFieldShouldReturnSingle(_ textField: UITextField, newString : String)
{
let nextTag: Int = textField.tag + 1
textField.text = newString
let nextResponder: UIResponder? = textField.superview?.viewWithTag(nextTag)
if let nextR = nextResponder
{
// Found next responder, so set it.
nextR.becomeFirstResponder()
}
else
{
// Not found, so remove keyboard.
textField.resignFirstResponder()
callOTPValidate()
}
}
}
Step 3:
create the textfield class for access the backward function
class MyTextField: UITextField {
weak var myTextFieldDelegate: MyTextFieldDelegate?
override func deleteBackward() {
if text?.isEmpty ?? false {
myTextFieldDelegate?.textFieldDidEnterBackspace(self)
}
super.deleteBackward()
}
}
protocol MyTextFieldDelegate: class {
func textFieldDidEnterBackspace(_ textField: MyTextField)
}
step - 4
finally follow the @Marmik Shah answer for custom class for your UITextField
Step 5
get the values from each textfield use this
func callOTPValidate(){
var texts: [String] = []
OTPTxtFields.forEach { texts.append($0.text!)}
sentOTPOption(currentText: texts.reduce("", +))
}
func sentOTPOption(currentText: String) {
print("AllTextfieldValue == \(currentText)")
}
How to make text typed in TextField undeletable?
The idea is the create UITextField class and use UIViewRepresentable to bind with SwiftUI view. By this, you can use all delegate methods and detect backspace. Also, using this you can prevent from cut and delete from tap action.
UndeletableTextField custom class
class UndeletableTextField: UITextField {
// This for prevent to cut and delete
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
if action == #selector(UIResponderStandardEditActions.delete(_:)) ||
action == #selector(UIResponderStandardEditActions.cut(_:)) {
return false
}
return super.canPerformAction(action, withSender: sender)
}
}
UIViewRepresentable view
struct UndeletableTextFieldUI: UIViewRepresentable {
@Binding var text: String
var placeholder: String
func makeUIView(context: Context) -> UndeletableTextField {
let textField = UndeletableTextField(frame: .zero)
textField.delegate = context.coordinator
textField.placeholder = placeholder
return textField
}
func updateUIView(_ uiView: UndeletableTextField, context: Context) {
uiView.text = text
}
func makeCoordinator() -> Coordinator {
Coordinator(parent: self)
}
class Coordinator: NSObject, UITextFieldDelegate {
var parent: UndeletableTextFieldUI
init(parent: UndeletableTextFieldUI) {
self.parent = parent
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
// Here we detect backspace and ignore it.
if let char = string.cString(using: String.Encoding.utf8) {
let isBackSpace = strcmp(char, "\\b")
if (isBackSpace == -92) {
print("Backspace was pressed")
return false
}
}
return true
}
}
}
ContentView
struct ContentView: View {
@State private var text: String = ""
var body: some View {
UndeletableTextFieldUI(text: $text, placeholder: "Type here")
}
}
What is the use of '\b' (backspace)
Backspace is a control character that moves the cursor one character back in the console but doesn't delete it.
What's the reason for the backspace character, and how might it be used?
It was used historically in the ASCII world to print accented characters.
For example à could be produced using the three character sequence a
Backspace
`
(or, using the characters' hex values, 0x61 0x08 0x60
).
See more on backspace here
Backspace key vs Backspace character
A lot of people confuse the two. Backspace key on keyboard has almost the universal function to delete the previous character (= move cursor back and delete that character). The backspace character '\b'
however only moves the cursor one position back in the console window and doesn't delete it.
Related Topics
Po Swift String "Unresolved Identifier"
Delete All Characters After a Certain Character from a String in Swift
How to Repeat Animation (Using Uiviewpropertyanimator) Certain Number of Times
Swift - How to Create a View with a Shape Cropped in It
How to Properly Implement the Equatable Protocol in a Class Hierarchy
How to Restrict the Type That a Function Throws in Swift
Result Values in '? :' Expression Have Mismatching Types 'Some View' and '...'
Evaluate Bool Property of Optional Object in If Statement
How to Use .Svg Images in Swiftui
Round Top Corners of a Uiview in Swift
Not Condition in 'If Case' Statement
Subclass.Fetchrequest() Swift 3.0, Extension Not Really Helping 100%
"Ambiguous Use of 'Propertyname'" Error Given Overridden Property with Didset Observer
How to Change the Uinavigationbar Title's Position
Timedmetadata' Deprecated. Another Method? <Updated>
Dispatch Group - Cannot Notify to Main Thread