How do I serialize an NSDictionary from a class implementation - Swift

in Objective-C, I use the following codes to serialize a custom class for a dictionary that works fine. To be familiar with Swift, porting Objective-C codes to Swift. However, I could not achieve this, how can I do this with Swift?

so I achieve with Objective-C

.h #import <Foundation/Foundation.h> #import <objc/runtime.h> @interface NSObject (aClass_NSDictionary) - (NSDictionary *)NSDictionaryFromClass; @end .m @implementation NSObject (aClass_NSDictionary) - (NSDictionary *)NSDictionaryFromClass { Class aClass = [self class]; u_int propertiesCount; objc_property_t *propertiesInAClass = class_copyPropertyList(aClass, &propertiesCount); NSMutableDictionary *propertiesDictionary = [[NSMutableDictionary alloc] initWithCapacity:propertiesCount]; for (int i = 0; i < propertiesCount; i++) { NSString *strAKey = [NSString stringWithCString:property_getName(propertiesInAClass[i]) encoding:NSUTF8StringEncoding]; [propertiesDictionary setValue:[self valueForKey:strAKey] forKey:strAKey]; } free(propertiesInAClass); return propertiesDictionary; } @end 

when I wrote the same code in swift, I could not find the equivalent of [self class] .

 class class2dicti : NSObject { class func nsdictionaryFromAClass() -> NSDictionary { let aClass = self.classForCoder var propertiesCount : u_int let propertiesInAClass : objc_property_t = class_copyPropertyList(aClass, &propertiesCount) //return NSDictionary() } } 

Update

so far i tried:

  let aClass = self.classForCoder var propertiesCount : u_int let propertiesInAClass : objc_property_t = class_copyPropertyList(aClass, &propertiesCount) 

and

 let aClass : AnyClass! = self.classForCoder() 

no success, all the same compiler error "Could not find overload for '__conversion', which takes the provided arguments

Decision

regarding the answers below, I found this solution and it worked. I basically created an extension for my class.

 class myClass : NSObject { var propertyOne = "prop One" var propertyTwo = [1, 2, 3] var propertyThree = ["A":1, "B":2, "C":3] } extension myClass { func toDictionary() -> NSDictionary { var aClass : AnyClass? = self.dynamicType var propertiesCount : CUnsignedInt = 0 let propertiesInAClass : UnsafePointer<objc_property_t> = class_copyPropertyList(aClass, &propertiesCount) var propertiesDictionary : NSMutableDictionary = NSMutableDictionary() for var i = 0; i < Int(propertiesCount); i++ { var strKey : NSString? = NSString(CString: property_getName(propertiesInAClass[i]), encoding: NSUTF8StringEncoding) propertiesDictionary.setValue(self.valueForKey(strKey), forKey: strKey) } return propertiesDictionary } } 

now this let myclazz = myClass().toDictionary() gives me an NSDictionary. All suggestions are welcome.

+6
source share
4 answers

In Swift, you never work with classes. You work with types:

 var clazz: AnyClass? = self.dynamicType class_copyPropertyList(clazz, nil) 

All Obj-C methods that return a Class , for example. classForCoder updated to use Swift ( AnyClass ) type instead.

Please note that you have other type problems:

 var propertiesCount : CUnsignedInt = 0 let propertiesInAClass : UnsafePointer<objc_property_t> = class_copyPropertyList(clazz, &propertiesCount) 

If you really need access to the Obj-C class as AnyObject , for example, to create an array of classes and pass it to Obj-C, see this

+1
source

This is how I implemented deep serialization.

If the DictionarySerializedObject property, then it is recursively serialized.

Be careful because class_copyPropertyList() does not return properties of additional Swift types such as Bool? , [String?] Because the Foundation does not provide bridges for them. For example, does it provide a bridge for Bool to NSNumber , but does not provide a bridge for Bool? .

 import Foundation protocol DictionarySerializable { func serializeToDictionary() -> [String:AnyObject] } class DictionarySerializableObject: NSObject { } extension NSObject: DictionarySerializable { func serializeToDictionary() -> [String:AnyObject] { var aClass: AnyClass? = self.dynamicType var propertiesCount: CUnsignedInt = 0 let properties = class_copyPropertyList(aClass, &propertiesCount) var dictionary = [String: AnyObject]() for var i = 0; i < Int(propertiesCount); i++ { if let name = NSString(CString: property_getName(properties[i]), encoding: NSUTF8StringEncoding) as? String { dictionary[name] = getDictionaryValueForObject(self.valueForKey(name)) } } free(properties) return dictionary } private func getDictionaryValueForObject(object: AnyObject?) -> AnyObject { if let object: AnyObject = object { if let object = object as? DictionarySerializableObject { return object.serializeToDictionary() } else if let object = object as? [AnyObject] { var array = [AnyObject]() for item in object { array.append(getDictionaryValueForObject(item)) } return array } else if let object = object as? NSData { return object.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(0)) } else { return object } } else { return NSNull() } } } 
+2
source

I use this method to archive everything that conforms to the NSCoding protocol.

first I get the url for the folder e.g. e.g. Documents :

 var error: NSError? let documentURL : NSURL = NSFileManager.defaultManager().URLForDirectory(NSSearchPathDirectory.DocumentDirectory, inDomain: NSSearchPathDomainMask.UserDomainMask, appropriateForURL: nil, create: true, error: &error) 

then I archive it to this folder:

 let object: AnyObject = // ... let filename: String = "<filename>" let customExtension: String = "<extension>" let urlForFile: NSURL = documentURL.URLByAppendingPathComponent(filename).URLByAppendingPathExtension(customExtension) let result: Bool = NSKeyedArchiver.archivedDataWithRootObject(object).writeToURL(urlForFile, atomically: true) 

and unarchive later is very similar to the recent path:

 let data: NSData = NSData.dataWithContentsOfFile(urlForFile.path, options: NSDataReadingOptions.DataReadingUncached, error: &error) let object: AnyObject = NSKeyedUnarchiver.unarchiveObjectWithData(data) 

NOTE. This is a raw example without checking anything, be it nil or handling a possible error. you may need to add them for your final code.

0
source

I wrote a c object library that automatically does this based on key values ​​and property names. I have a branch to support Swift classes, and it works well. https://github.com/aryaxt/OCMapper

0
source

Source: https://habr.com/ru/post/970834/


All Articles