NSTextField set max character length using Formatter

Hi, I'm trying use Formatter for NSTextField to set maximum string length.


I found this https://stackoverflow.com/questions/827014/how-to-limit-nstextfield-text-length-and-keep-it-always-upper-case


But it's for objective-c. I tried this for swift, but it's not working


func controlTextDidChange(_ obj: Notification) {
        
        if let info = obj.userInfo, let text = info["NSFieldEditor"] as? NSText {
            let formatter = TextFieldFormatter()
            formatter.maxLength = 10
            let string = text.string
            
            text.string = formatter.string(for: string.capitalized)!
        }
        
}


Custom formatter class:


class TextFieldFormatter: Formatter {
    
    var maxLength = 0
    
    func setMaximumLength(_ len: Int) {
        maxLength = len
    }
    
    func maximumLength() -> Int {
        return maxLength
    }
    
    override init() {
        super.init()
        maxLength = Int(Int32.max)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func string(for obj: Any?) -> String? {
        return obj as? String
    }
    
    override func getObjectValue(_ obj: AutoreleasingUnsafeMutablePointer<AnyObject?>?, for string: String, errorDescription error: AutoreleasingUnsafeMutablePointer<NSString?>?) -> Bool {
        
        obj?.pointee = string as AnyObject
        return true
        
    }
    
    override func isPartialStringValid(_ partialStringPtr: AutoreleasingUnsafeMutablePointer<NSString>, proposedSelectedRange proposedSelRangePtr: NSRangePointer?, originalString origString: String, originalSelectedRange origSelRange: NSRange, errorDescription error: AutoreleasingUnsafeMutablePointer<NSString?>?) -> Bool {
        
        let size = partialStringPtr.pointee.length
        if size > maxLength {
            return false
        } else {
            return true
        }
        
    }
    
}
Answered by Claude31 in 412910022

I would do this, no need for formatter I think:


func controlTextDidChange(_ obj: Notification) {
    guard let textField = obj.object as? NSTextField else { return }
    if textField === theTextField {     // THIS NOT NEEDED IF ONLY ONE TEXTFIELD
            let newLength = textField.stringValue.count
            if newLength > 10 {
                let newStr = String(textField.stringValue.prefix(10))     // Skip after 10
                theTextField.stringValue = newStr
            }
    }
}


but it's not working

What do you test (type afetr 10 chars ?). What do you get ?

If you want to test with formatter, you should instrument code to understand what's going on.


    override func isPartialStringValid(_ partialStringPtr: AutoreleasingUnsafeMutablePointer, proposedSelectedRange proposedSelRangePtr: NSRangePointer?, originalString origString: String, originalSelectedRange origSelRange: NSRange, errorDescription error: AutoreleasingUnsafeMutablePointer<nsstring?>?) -> Bool {
        
        let size = partialStringPtr.pointee.length
        print("Size is", size, "Pointee", partialStringPtr.pointee, "maxLength", maxLength)
        if size > maxLength {
            return false
        } else {
            return true
        }
        
    }
Accepted Answer

I would do this, no need for formatter I think:


func controlTextDidChange(_ obj: Notification) {
    guard let textField = obj.object as? NSTextField else { return }
    if textField === theTextField {     // THIS NOT NEEDED IF ONLY ONE TEXTFIELD
            let newLength = textField.stringValue.count
            if newLength > 10 {
                let newStr = String(textField.stringValue.prefix(10))     // Skip after 10
                theTextField.stringValue = newStr
            }
    }
}


but it's not working

What do you test (type afetr 10 chars ?). What do you get ?

If you want to test with formatter, you should instrument code to understand what's going on.


    override func isPartialStringValid(_ partialStringPtr: AutoreleasingUnsafeMutablePointer, proposedSelectedRange proposedSelRangePtr: NSRangePointer?, originalString origString: String, originalSelectedRange origSelRange: NSRange, errorDescription error: AutoreleasingUnsafeMutablePointer<nsstring?>?) -> Bool {
        
        let size = partialStringPtr.pointee.length
        print("Size is", size, "Pointee", partialStringPtr.pointee, "maxLength", maxLength)
        if size > maxLength {
            return false
        } else {
            return true
        }
        
    }
NSTextField set max character length using Formatter
 
 
Q