10

I have an NSFormatter in Swift, which is attached to an NSTextField. It prevents illegal characters from being entered, but when I try to access the value of the next field it gives a nil value.

Below is the class:

class PSEntryNameFormatter : NSFormatter {
    override func stringForObjectValue(obj: AnyObject?) -> String? {

        if obj == nil {
            println("stringForObjectValue: obj is nil, returning nil")
            return nil
        }
        if let o = obj as? String {
                println("stringForObjectValue:  obj is string, returning \(o)")
                return o
            }

        println("stringForObjectValue: obj is not string, returning nil")
        return nil
    }

    override func getObjectValue(obj: AutoreleasingUnsafeMutablePointer<AnyObject?>, forString string: String, errorDescription error: AutoreleasingUnsafeMutablePointer<NSString?>) -> Bool {
        println("getObjectValue: \(string)")
        let obj = string
        return true
    }

    override func isPartialStringValid(partialString: String?, newEditingString newString: AutoreleasingUnsafeMutablePointer<NSString?>, errorDescription error: AutoreleasingUnsafeMutablePointer<NSString?>) -> Bool {
        if let s = partialString {
            var illegals : String = join("",s.componentsSeparatedByCharactersInSet(PSEntryNameFormatterCharacterSet))
            var goods = s.componentsSeparatedByCharactersInSet(NSCharacterSet(charactersInString: illegals))
            let newString : NSString = join("", goods)

            if String(newString) == s {
                println("isPartialStringValid: partial string ok")
                return true
            }
        }

        println("isPartialStringValid: partial string bad")
        return false
    }
}

And here is how I try to access:

func control(control: NSControl, textShouldEndEditing fieldEditor: NSText) -> Bool {
    println("Text should end editing")
    if (control == nameTextField) {
        var name = nameTextField.objectValue as String
        setObjectName(name)
    }
    return true
}

For debugging I add the println statements, and here is what happens when the textfield is set to 'Template' and then I delete two characters:

stringForObjectValue:  obj is string, returning Template
stringForObjectValue:  obj is string, returning Template
isPartialStringValid: partial string ok
getObjectValue: Templat
isPartialStringValid: partial string ok
getObjectValue: Templa

Then I press enter:

getObjectValue: Templa
Text should end editing 
getObjectValue: Templa
stringForObjectValue: obj is nil, returning nil
getObjectValue:
stringForObjectValue: obj is nil, returning nil
stringForObjectValue: obj is nil, returning nil
fatal error: unexpectedly found nil while unwrapping an Optional value

And then it crashes on the line when I cast to string. Obviously I can prevent the crash, but first I want to find out why it is returning nil. Any help very much appreciated!

James Alvarez
  • 7,159
  • 6
  • 31
  • 46

2 Answers2

14

The problem is in your getObjectValue function.

You should be assigning the value in this manner:

obj.memory = string

instead of

let obj = string
Kevin
  • 185
  • 2
  • 7
  • Thanks this works - do you have any more explanation i.e. where did you find out how to do this? – James Alvarez Jan 11 '15 at 11:28
  • I asked over on the Apple Discussion boards and got this answer: https://forums.developer.apple.com/message/44288#44288 – ericg Aug 23 '15 at 18:12
  • 2
    Thanks for this! obj.memory = string didn't work for me - xcode was complaining that memory is a get-only property, but obj?.pointee = string as AnyObject did work. – JohnV Sep 26 '18 at 06:31
0

I have a similar problem and got a partial fix:

override func stringForObjectValue(obj: AnyObject) -> String? {
  if let desc = obj.description {
    println("sFO=\(obj)")
  } else {
    println("sFO=nil")
  }
  return obj.description
}

But each time I tab out of the field its contents is set to nil again. Still stuck with that. I had no issue with the analog OC code.

qwerty_so
  • 35,448
  • 8
  • 62
  • 86
  • 1
    I finally gave up using the formatter and used NSTextFieldDelegate/controlTextDidChange to check whatever was entered and react accordingly. Honestly, the resulting code was even more readable. – qwerty_so Nov 01 '14 at 22:54
  • This didn't solve the issue unfortunately, I think it is a bug. Sorry I cannot accept the answer, but will upvote your comment. – James Alvarez Nov 12 '14 at 13:47