2

I am trying to get the property list of a swift class. There is a similar question here and here. I have everything working except for certain types do not get returned from class_copyPropertyList. The ones I have tested it with so far are Int? and enums. I have an example class below of what I am trying.

enum PKApiErrorCode: Int {
    case None = 0
    case InvalidSignature = 1
    case MissingRequired = 2
    case NotLoggedIn = 3
    case InvalidApiKey = 4
    case InvalidLogin = 5
    case RegisterFailed = 6
}

class ApiError: Serializable {
    let code: PKApiErrorCode?
    let message: String?
    let userMessage: String?

    init(error: JSONDictionary) {
        code = error["errorCode"] >>> { (object: JSON) -> PKApiErrorCode? in
            if let c = object >>> JSONInt {
                return PKApiErrorCode.fromRaw(c)
            }

            return nil
        }

        message = error["message"] >>> JSONString
        userMessage = error["userMessage"] >>> JSONString
    }
}

And the Serializable class (with some help from https://gist.github.com/turowicz/e7746a9c035356f9483d is

public class Serializable: NSObject, Printable {
    override public var description: String {
        return "\(self.toDictionary())"
    }
}

extension Serializable {
     public func toDictionary() -> NSDictionary {
        var aClass : AnyClass? = self.dynamicType
        var propertiesCount : CUnsignedInt = 0
        let propertiesInAClass : UnsafeMutablePointer<objc_property_t> = class_copyPropertyList(aClass, &propertiesCount)
        var propertiesDictionary : NSMutableDictionary = NSMutableDictionary()
        for var i = 0; i < Int(propertiesCount); i++ {

            var property = propertiesInAClass[i]
            var propName = NSString(CString: property_getName(property), encoding: NSUTF8StringEncoding)
            var propType = property_getAttributes(property)
            var propValue : AnyObject! = self.valueForKey(propName);
            if propValue is Serializable {
                propertiesDictionary.setValue((propValue as Serializable).toDictionary(), forKey: propName)
            } else if propValue is Array<Serializable> {
                var subArray = Array<NSDictionary>()
                for item in (propValue as Array<Serializable>) {
                    subArray.append(item.toDictionary())
                }
                propertiesDictionary.setValue(subArray, forKey: propName)
            } else if propValue is NSData {
                propertiesDictionary.setValue((propValue as NSData).base64EncodedStringWithOptions(nil), forKey: propName)
            } else if propValue is Bool {
                propertiesDictionary.setValue((propValue as Bool).boolValue, forKey: propName)
            } else if propValue is NSDate {
                var date = propValue as NSDate
                let dateFormatter = NSDateFormatter()
                dateFormatter.dateFormat = "Z"
                var dateString = NSString(format: "/Date(%.0f000%@)/", date.timeIntervalSince1970, dateFormatter.stringFromDate(date))
                propertiesDictionary.setValue(dateString, forKey: propName)

            } else {
                propertiesDictionary.setValue(propValue, forKey: propName)
            }
        }

        return propertiesDictionary
    }

    public func toJSON() -> NSData! {
        var dictionary = self.toDictionary()
        var err: NSError?
        return NSJSONSerialization.dataWithJSONObject(dictionary, options:NSJSONWritingOptions(0), error: &err)
    }

    public func toJSONString() -> NSString! {
        return NSString(data: self.toJSON(), encoding: NSUTF8StringEncoding)
    }
}

The String seem to only appear if the Optionals are valid values and the code never appears on the object if it is an enum or Int unless the Int has a default value.

Thanks for any advice I can get for getting all properties of a class no matter what they are.

Community
  • 1
  • 1
smitt04
  • 3,018
  • 2
  • 28
  • 30
  • Is there anyone who even has a clue where to begin, or does anyone need more info? – smitt04 Sep 08 '14 at 14:10
  • I have this exact same issue, using the same gist. It's been a month on this question. Any updates? I keep shaking my head thinking that there has got to be a straightforward way to serialize a swift class, but I've yet to find one that works end-to-end. – Albert Bori Oct 15 '14 at 22:34

1 Answers1

4

I got a response on the apple developer forums regarding this issue:

"class_copyPropertyList only shows properties that are exposed to the Objective-C runtime. Objective-C can't represent Swift enums or optionals of non-reference types, so those properties are not exposed to the Objective-C runtime."

Source

So, in summary, serialization to JSON using this approach is not currently possible. You might have to look into using other patterns to accomplish this, such as giving the task of serialization to each object, or potentially by using the reflect() method to serialize an object to JSON.

Albert Bori
  • 9,832
  • 10
  • 51
  • 78