Custom NSFormatter returning nil in swift - macos

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!

The problem is in your getObjectValue function.
You should be assigning the value in this manner:
obj.memory = string
instead of
let obj = string

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.

Related

Why do I get "Composite Literal Uses Unkeyed" error?

I'm relatively new to Go and am working on building out a request decoder. The request comes in JSON format and we decode that to a map[string]interface{}. We then pass that object data in to be decoded to our own ProcessRequest struct. As I said I'm new so I am reusing some logic in similar parts of the code wrote by previous developers. Essentially we are checking the map for the necessary pieces and then setting and returning those. Can someone explain to me why I am getting the titled error? Would I have to set the items all the way down to base structs that no longer have any nested? Is there a better way to accomplish what I want? Here is the code and the related structs. It is highlighting the error on the return of the model.ProcessRequest. TYIA
type ProcessRequest struct {
RequestID string
Message *message.Message
Rule *Rule
Options *ProcessOptions
//TODO: Context EvaluatorContext
//TODO: Links
}
type Message struct {
ID int
Key string
Source string
Headers *HeaderSet
Categories *CategorySet
Properties *PropertySet
Streams *StreamSet
}
type RuleAction struct {
Name string
Expression map[string]interface{}
}
type RuleLink struct {
LinkID int
Condition map[string]interface{}
TargetRuleID int
}
type Rule struct {
Name string
Code string
Actions []RuleAction
Links []RuleLink
}
type object = map[string]interface{}
func DecodeProcessRequest(dataObject map[string]interface{}) (*model.ProcessRequest, error) {
var (
requestID string
message *message.Message
rule *model.Rule
options *model.ProcessOptions
err error
)
if reqIDSrc, ok := dataObject["requestId"]; ok {
if requestID, err = converter.ToString(reqIDSrc); err != nil {
return nil, errors.Wrapf(err, "Error reading property 'requestID'")
}
if requestID == "" {
return nil, errors.Errorf("Property 'requestID' is an empty string")
}
} else {
return nil, errors.Errorf("Missing required property 'requestID'")
}
if messageSrc, ok := dataObject["message"]; ok {
messageData, ok := messageSrc.(object)
if !ok {
return nil, errors.Errorf("Error reading property 'message': Value is not an object")
}
if message, err = DecodeMessage(messageData); err != nil {
return nil, errors.Wrapf(err, "Error reading property 'message'")
}
} else {
return nil, errors.Errorf("Missing required property 'message'")
}
if ruleSrc, ok := dataObject["rule"]; ok {
ruleObj, ok := ruleSrc.(object)
if !ok {
return nil, errors.Errorf("Error reading property 'rule': Value is not an object")
}
if rule, err = DecodeRule(ruleObj); err != nil {
return nil, errors.Wrapf(err, "Error reading 'rule' during decoding")
}
} else {
return nil, errors.Errorf("Missing required property 'requestID'")
}
// Parse plain object to a Message struct
return &model.ProcessRequest{
requestID,
message,
rule,
options,
}, nil
}
super said in this comment:
In general, the warning says that you should prefer to use the syntax ProcessRequest{ RequestID: requestID, ... }. Naming the keys instead of unkeyed values.
That worked for me. Also the explanation by kostix in this comment really helped.
Basically the idea is that if you use "unkeyed" way of defining struct literals, the meaning of your definitions depends on the way the fields of the underlying type are layed out. Now consider that your type has three fields of type string in a certain order. Now a couple of iterations down the road some programmer moves the second field to the 1st position—your literal will still compile but will end up defining a completely different value at runtime.

How to use the error interface

I have source like the following:
type Record struct {
Message string `json:"message"`
Service string `json:"service"`
Success bool `json:"success"`
Error string `json:"error"`
}
func (zp *Zephyr) Write(err ...*error) {
if len(err) > 0 {
errPtr := err[0]
if errPtr != nil && *errPtr != nil {
// error occurred, set success to false and Error to the error message
zp.Success = false
zp.Error = errPtr
} else {
zp.Success = true
}
}
}
What I don't understand is how can I access the string that is embedded in errPtr?
First, you likely don't want *error, you most likely just want error; pointers to interfaces are very seldom the correct choice.
Second, there isn't necessarily a string embedded in an error. The definition of error is nothing more than:
type error interface {
Error() string
}
Meaning if you call the Error() method, it will return a string, but it may be generated every time the method is called; it's not necessarily a string field in the error object.
Most likely, what you want is something like this:
func (zp *Zephyr) Write(err ...error) {
if len(err) > 0 {
errPtr := err[0]
if errPtr != nil {
// error occurred, set success to false and Error to the error message
zp.Success = false
zp.Error = errPtr.Error()
} else {
zp.Success = true
}
}
}
If you can't change the signature, you just need to dereference the pointer:
zp.Error = (*errPtr).Error()
Playground example here: https://play.golang.org/p/dxT108660l
Errors are also covered in the Go tour.

Implementing Redigo Scanner interface on a struct's field

I have a struct that looks like this:
type authEnum int
const (
never authEnum = iota
sometimes
always
)
type Attrs struct {
Secret string `redis:"secret"`
RequireSecret authEnum `redis:"requireSecret"`
UserID string `redis:"userId"`
}
func (e *authEnum) RedisScan(src interface{}) error {
// This never gets called!
if e == nil {
return fmt.Errorf("nil pointer")
}
switch src := src.(type) {
case string:
if src == "false" || src == "never" {
*e = never
} else if src == "sometimes" {
*e = sometimes
} else { // "always" or "true"
*e = always
}
default:
return fmt.Errorf("cannot convert authEnum from %T to %T", src, e)
}
return nil
}
func getAttributes(ctx *AppContext, hash string) (*Attrs, error) {
rc := ctx.RedisPool.Get()
values, err := redis.Values(rc.Do("HGETALL", "redishash"))
rc.Close()
if err != nil {
return nil, err
}
attrs := Attrs{}
redis.ScanStruct(values, &attrs)
return &attrs, nil
}
How do I implement the Scanner interface on the RequireSecret attribute to parse an authEnum type out of "never", "sometimes" or "always" redis hash values?
How do I calculate the value and assign it to the authEnum?
In my code example RedisScan never gets called.
You don't implement interfaces on fields, but rather on types.
You can make your authEnum type satisfy the interface, simply by creating a method with the signature RedisScan(src interface{}) error on that type.
To assign to the receiver, you need to receive a pointer. Then you can assign to it as so:
func (e *authEnum) RedisScan(src interface{}) error {
var value authEnum
// Logic here to convert src to value
*e = value
}
Implement the method on a pointer receiver. Redis bulk strings are represented as []byte, not string:
func (e *authEnum) RedisScan(src interface{}) error {
b, ok := src.([]byte)
if !ok {
return fmt.Errorf("cannot convert authEnum from %T to %T", src, b)
}
switch string(b) {
case "false", "never":
*e = never
case "sometimes":
*e = sometimes
default:
*e = always
}
return nil
}
Always check and handle errors. The error returned from ScanStruct reports the type problem.
There's no need to check for nil pointer to the struct member. If the argument to ScanStruct is nil, then Redigo will panic well before the RedisScan method is called.

How can I properly UnMarshal json into a defined struct

I get the error "cannot unmarshal object into Go value of type []main.parsed" when I try this
package main
import {...}
type parsed struct {
Title string `json:"title,string,omitempty"`
}
func Function (args [] String) string {
var jsonData [] parsed
body, err := ioutil.ReadAll(resp.Body)
if err!= nil {
return ""
}
err = json.Unmarshal([]byte(body), &jsonData)
if err!= nil {
return ""
}
fmt.Println(jsonData)
}
it seems the format is {"id":"value",...} rather than [{"id", "value"}, {}...]
Try replacing
var jsonData [] parsed
with
var jsonData parsed

'(String) -> String' is not convertible to 'SQLHandler'

The line below, at SQLHandler.translateQuery("Do mysql stuff"), is throwing the error: '(String) -> String' is not convertible to 'SQLHandler'. Why is it doing this? Thank you in advance.
Code 1 (Used wherever and whenever needed)
var query: String = "mysql stuff"
SQLHandler.sendQuery(SQLHandler.translateQuery("domain and \(query)"))
Code 2, SQLHandler.swift (Called whenever needed)
import Foundation
class SQLHandler {
func translateQuery(queryToTranslate: String) -> String{
println(queryToTranslate)
return queryToTranslate.stringByReplacingOccurrencesOfString(" ", withString: "_", options: NSStringCompareOptions.LiteralSearch, range: nil)
}
func sendQuery(query: String){
println(query)
let url = NSURL(string: "url and query goes here")
let task = NSURLSession.sharedSession().dataTaskWithURL(url!, completionHandler: { (data, response, error) -> Void in })
task.resume()
}
}
You are calling an instance method on the class itself.
Either create an instance and call the method:
var sqlHandler = SQLHandler()
sqlHandler.translateQuery("domain and \(query)")
or define the methods as class methods :
class func translateQuery(queryToTranslate: String) -> String ...
class func sendQuery(query: String) ...

Resources