@@ -96,8 +96,10 @@ public class NSJSONSerialization : NSObject {
96
96
97
97
/* Generate JSON data from a Foundation object. If the object will not produce valid JSON then an exception will be thrown. Setting the NSJSONWritingPrettyPrinted option will generate JSON with whitespace designed to make the output more readable. If that option is not set, the most compact possible JSON will be generated. If an error occurs, the error parameter will be set and the return value will be nil. The resulting data is a encoded in UTF-8.
98
98
*/
99
- public class func dataWithJSONObject( obj: AnyObject , options opt: NSJSONWritingOptions ) throws -> NSData {
100
- NSUnimplemented ( )
99
+ public class func dataWithJSONObject( obj: Any , options opt: NSJSONWritingOptions ) throws -> NSData {
100
+ let ( newIndent, newLine, spacing) = opt. contains ( NSJSONWritingOptions . PrettyPrinted) ? ( " \t " , " \n " , " " ) : ( " " , " " , " " )
101
+ let str = NSString ( try JSONSerialize ( obj, newIndent: newIndent, newLine: newLine, space: spacing, topLevel: true ) )
102
+ return str. dataUsingEncoding ( NSUTF8StringEncoding) !
101
103
}
102
104
103
105
/* Create a Foundation object from JSON data. Set the NSJSONReadingAllowFragments option if the parser should allow top-level objects that are not an NSArray or NSDictionary. Setting the NSJSONReadingMutableContainers option will make the parser generate mutable NSArrays and NSDictionaries. Setting the NSJSONReadingMutableLeaves option will make the parser generate mutable NSString objects. If an error occurs during the parse, then the error parameter will be set and the result will be nil.
@@ -147,6 +149,119 @@ public class NSJSONSerialization : NSObject {
147
149
}
148
150
}
149
151
152
+ // MARK: - Serialization
153
+ private extension NSJSONSerialization {
154
+
155
+ private class func escapeStringForJSON( string: String ) -> String {
156
+ return NSString ( NSString ( string) . stringByReplacingOccurrencesOfString ( " \\ " , withString: " \\ \\ " ) ) . stringByReplacingOccurrencesOfString ( " \" " , withString: " \\ \" " )
157
+ }
158
+ private class func serializeArray< T> ( array: [ T ] , newIndent: String , newLine: String , space: String , indentation: String ) throws -> String {
159
+ guard array. count > 0
160
+ else {
161
+ return " \( indentation) [] "
162
+ }
163
+ var index = 0
164
+ return try array. reduce ( " \( indentation) [ \( newLine) " , combine: {
165
+ index += 1
166
+ let separator = ( index == array. count) ? " \( newLine) \( indentation) ] " : " , \( newLine) "
167
+ return $0 + ( try JSONSerialize ( $1, newIndent: newIndent, newLine: newLine, space: space, indentation: indentation + newIndent) ) + separator
168
+ } )
169
+ }
170
+
171
+ private class func serializePOD< T: Any > ( object: T , indentation: String ) throws -> String {
172
+ if let str = object as? String {
173
+ return indentation + " \" \( escapeStringForJSON ( str) ) \" "
174
+ } else if let _ = object as? NSNull {
175
+ return indentation + " null "
176
+ } else if let obj = object as? CustomStringConvertible {
177
+ // Using CustomStringConvertible is a hack to allow for all POD types
178
+ // Once bridging works we can revert back.
179
+ // TODO: Fix when bridging works
180
+ return indentation + escapeStringForJSON( obj. description)
181
+ }
182
+ else if let num = object as? NSNumber {
183
+ return num. description
184
+ } else {
185
+ throw NSError ( domain: NSCocoaErrorDomain, code: NSCocoaError . PropertyListWriteInvalidError. rawValue, userInfo: [
186
+ " NSDebugDescription " : " Cannot serialize \( object. dynamicType) "
187
+ ] )
188
+ }
189
+ }
190
+
191
+ private class func serializeObject< T> ( object: [ String : T ] , newIndent: String , newLine: String , space: String , indentation: String ) throws -> String {
192
+ guard object. count > 0
193
+ else {
194
+ return " \( indentation) {} "
195
+ }
196
+ var index = 0
197
+ return try object. reduce ( " \( indentation) { \( newLine) " , combine: {
198
+ let valueString : String
199
+ do {
200
+ valueString = try serializePOD ( $1. 1 , indentation: " " )
201
+ }
202
+ catch {
203
+ valueString = try JSONSerialize ( $1. 1 , newIndent: newIndent, newLine: newLine, space: space, indentation: indentation + newIndent)
204
+ }
205
+ index += 1
206
+ let separator = ( index == object. count) ? " \( newLine) \( indentation) } " : " , \( newLine) "
207
+ return $0 + " \( indentation + newIndent) \" " + escapeStringForJSON( $1. 0 ) + " \" \( space) : \( space) " + valueString + separator
208
+ } )
209
+ }
210
+
211
+ private class func JSONSerialize< T> ( object: T , newIndent: String , newLine: String , space: String , topLevel: Bool = false , indentation: String = " " ) throws -> String {
212
+ // TODO: - revisit this once bridging story gets fully figured out
213
+ if let array = object as? [ Any ] {
214
+ return try serializeArray ( array, newIndent: newIndent, newLine: newLine, space: space, indentation: indentation)
215
+ } else if let array = object as? NSArray {
216
+ return try serializeArray ( array. bridge ( ) , newIndent: newIndent, newLine: newLine, space: space, indentation: indentation)
217
+ } else if let array = object as? [ NSNumber ] {
218
+ return try serializeArray ( array, newIndent: newIndent, newLine: newLine, space: space, indentation: indentation)
219
+ } else if let array = object as? [ String ] {
220
+ return try serializeArray ( array, newIndent: newIndent, newLine: newLine, space: space, indentation: indentation)
221
+ } else if let array = object as? [ Double ] {
222
+ return try serializeArray ( array, newIndent: newIndent, newLine: newLine, space: space, indentation: indentation)
223
+ } else if let array = object as? [ Int ] {
224
+ return try serializeArray ( array, newIndent: newIndent, newLine: newLine, space: space, indentation: indentation)
225
+ } else if let array = object as? [ Bool ] {
226
+ return try serializeArray ( array, newIndent: newIndent, newLine: newLine, space: space, indentation: indentation)
227
+ } else if let array = object as? [ Float ] {
228
+ return try serializeArray ( array, newIndent: newIndent, newLine: newLine, space: space, indentation: indentation)
229
+ } else if let array = object as? [ UInt ] {
230
+ return try serializeArray ( array, newIndent: newIndent, newLine: newLine, space: space, indentation: indentation)
231
+ } else if let dict = object as? [ String : Any ] {
232
+ return try serializeObject ( dict, newIndent: newIndent, newLine: newLine, space: space, indentation: indentation)
233
+ } else if let dict = object as? NSDictionary {
234
+ return try JSONSerialize ( dict. bridge ( ) , newIndent: newIndent, newLine: newLine, space: space, topLevel: topLevel, indentation: indentation)
235
+ } else if let dict = object as? [ String : String ] {
236
+ return try serializeObject ( dict, newIndent: newIndent, newLine: newLine, space: space, indentation: indentation)
237
+ } else if let dict = object as? [ String : Double ] {
238
+ return try serializeObject ( dict, newIndent: newIndent, newLine: newLine, space: space, indentation: indentation)
239
+ } else if let dict = object as? [ String : Int ] {
240
+ return try serializeObject ( dict, newIndent: newIndent, newLine: newLine, space: space, indentation: indentation)
241
+ } else if let dict = object as? [ String : Bool ] {
242
+ return try serializeObject ( dict, newIndent: newIndent, newLine: newLine, space: space, indentation: indentation)
243
+ } else if let dict = object as? [ String : Float ] {
244
+ return try serializeObject ( dict, newIndent: newIndent, newLine: newLine, space: space, indentation: indentation)
245
+ } else if let dict = object as? [ String : UInt ] {
246
+ return try serializeObject ( dict, newIndent: newIndent, newLine: newLine, space: space, indentation: indentation)
247
+ } else if let dict = object as? [ String : NSNumber ] {
248
+ return try serializeObject ( dict, newIndent: newIndent, newLine: newLine, space: space, indentation: indentation)
249
+ }
250
+ // This else if situation will greatly improve once bridging works properly.
251
+ // For now we check for Floats, Doubles, Int, UInt, Bool and NSNumber
252
+ // but this may disallow other types like CGFloat, Int32, etc which is a problem
253
+ else {
254
+ guard !topLevel
255
+ else {
256
+ throw NSError ( domain: NSCocoaErrorDomain, code: NSCocoaError . PropertyListWriteInvalidError. rawValue, userInfo: [
257
+ " NSDebugDescription " : " Unable to use \( object. dynamicType) as a top level JSON object. "
258
+ ] )
259
+ }
260
+ return try serializePOD ( object, indentation: indentation)
261
+ }
262
+ }
263
+ }
264
+
150
265
//MARK: - Encoding Detection
151
266
152
267
internal extension NSJSONSerialization {
0 commit comments