Disabling the Send Button Challenge

I’m stuck on how to get the Send button enabled once some text has been entered into the message field. I’ve created the IsNotEmptyTransformer class:

[code]import Cocoa

class IsNotEmptyTransformer: NSValueTransformer {

class func transformedValueClass(value: AnyObject?) -> AnyObject? {
	return IsNotEmptyTransformer.self
}

class override func allowsReverseTransformation () -> Bool {
	return false
}

class func transformedValue(value: AnyObject?) -> AnyObject? {
	return !(value!.message == "")
}

}
[/code]

I’ve registered the transformer in the AppDelegate:

[code] dynamic var isNotEmptyTransformer = IsNotEmptyTransformer()

func applicationDidFinishLaunching(aNotification: NSNotification) {
	// Insert code here to initialize your application
	NSValueTransformer.setValueTransformer(isNotEmptyTransformer, forName: "IsNotEmptyTransformer")
	addWindowController()
}

[/code]

And, I’ve set the Send button’s Value binding to message in the Model Key Path and in the ValueTransformer I’ve set the IsNotEmptyTransformer class. I also set the message text field’s Continuously Updates Value on.

When I run the program, the Send button is always disabled. Entering text into the message text field does not change the button’s enabled state. I’ve also set breakpoints on all the IsNotEmptyTransformer’s methods and none of them is ever being called. I’ve verified in the debugger that the IsNotEmptyTransformer has in fact been registered. I’m at a dead end, I don’t understand why the transformer’s methods are not being called. What am I missing that is preventing the button from becoming enabled with the text entry?

Thanks,

Brian

Brian,

I did it slightly differently:

  • I registered the transformer in the AppDelegate as you had

  • I bound the button to the value transformer NSIsNotNil with no code implemented in the class

  • In ChatWindowControlller.swift, in the @IBAction function for the button send, I changed the code like this -

from:

to:

Tom

Thanks Tom, I’ll give that a try.

That worked like a charm and was way too easy. :slight_smile:

Thanks again Tom.

[quote=“BrianLawson”]That worked like a charm and was way too easy. :slight_smile:

Thanks again Tom.[/quote]
Cool, glad it worked! :slight_smile:

Hi, after much effort I finally figured it out.
transformedValueClass: must return an NSNumber

class func transformedValueClass(value: AnyObject?) -> AnyObject? { return NSNumber.self }
transformedValue: is not a class method

override func transformedValue(value: AnyObject?) -> AnyObject? { if value == nil { println("Message is nil") return NSNumber(bool: false) } let message = value as! String let answer = !message.isEmpty return NSNumber(bool: answer) }
and you register the transformer in AppDelegate’s applicationDidFinishLaunching: method

func applicationDidFinishLaunching(aNotification: NSNotification) { NSValueTransformer.setValueTransformer(IsNotEmptyTransformer(), forName: "IsNotEmptyTransformer") let stringNotEmptyTransformer = NSValueTransformer(forName: "IsNotEmptyTransformer") addWindowController() }

Not as neat as using NSIsNotNil, but at least I finally got my own Value Transformer working :smiley:

I did mine in a different way. I created and registered in the app delegate as Brian did. Then I did this in my transformer class:

class IsNotEmptyTransformer: NSValueTransformer {
    override func transformedValue(value: AnyObject?) -> AnyObject? {
        if let string = value as! String? {
            return !string.isEmpty
        } else {
            return false;
        }
    }
}

Works without issue.

Hi,

Personnaly, I adopted an other way to do so by declaring a new variable

dynamic var message: String? { didSet { if let message = message { messageIsNotEmply = (message.characters.count > 0) } else { messageIsNotEmply = false } } } dynamic var messageIsNotEmply: Bool = false

Thank you

Hi,

I just want to say that your solution, Nicox05, is the more simple and elegant one ! Bravo !

Thanks

Complete solution with NSValueTransformer (though I agree that a variable is a more elegant solution):

The IsNotEmptyTransformer class:

import Foundation

class IsNotEmptyTransformer: NSValueTransformer {
    
    override class func transformedValueClass() -> AnyClass {
        return Bool.self as! AnyClass
    }
    
    override class func allowsReverseTransformation() -> Bool {
        return false
    }
    
    override func transformedValue(value: AnyObject?) -> AnyObject? {
        if let value = value as? String {
            return value.characters.count > 0
        } else {
            return false
        }
    }
    
}

Add this to AppDelegate’s didFinishLaunching method:

NSValueTransformer.setValueTransformer(IsNotEmptyTransformer(), forName: "isNotEmptyTransformer")

Under the Send button’s Availability section set Model Key Path to message and Value Transformer to isNotEmptyValueTransformer. Note that it begins with a lowercase i, meaning that instead of the class name you should provide the name under which you registered it in the AppDelegate.

Nowadays, @objc() is necessary for IB to recognize le value transformer connection. That gives :

@objc(IsNotEmptyTransformer) class IsNotEmptyTransformer: ValueTransformer {

override func transformedValue(_ value: Any?) -> Any? {
    if (value as! String?) != nil {
        return true
    } else {
        return false
    }
}

with
ValueTransformer.setValueTransformer(IsNotEmptyTransformer(), forName: NSValueTransformerName(“IsNotEmptyTransformer”))

in applicationDidFinishLaunching of AppDelegate. Finally, I also had to make an outlet to the sendButton just to be able to disable it once the text had been sent.