I want to print a pretty-printed representation of a JSON I get from the server.
The JSON has many string values in Hebrew.
I noticed that when the output is printed in the debug console, sometimes I see the symbol "327\" inserted inside some of the texts. The location is inconsistent.
Example:
"Description" : "מעבדות קורונה",
"DictionaryPlaceholder" : "ל\327דוגמא : ראש העין",
And if I print the RAW value of the same JSON, it isn't pretty but the string is correct:
\"Description\":\"מעבדות קורונה\",\"DictionaryPlaceholder\":\"לדוגמא : ראש העין\",
The additional 327\ creates parsing issues when I copy the JSON from the console and try to parse it in other systems.
This is the relevant code:
private let separator = "\n"
private let terminator = "\n==========================================\n"
private func logNetworkResponse(_ response: URLResponse?, data: Data?, target: TargetType) -> String {
var output = String()
output.append("[\(date)]\(separator)")
if let data = data {
if let pretty = data.prettyJSON {
output.append("\(target) (pretty-printed) Response: \(pretty)")
} else if let string = String(data: data, encoding: .utf8) {
output.append("\(target) (raw) Response: \(string))")
}
}
output.append(terminator)
return output
}
extension Data {
var prettyJSON: String? {
guard let jsonObject = try? JSONSerialization.jsonObject(with: self) else {
return nil
}
var pretty: Data?
if #available(iOS 13.0, *) {
pretty = try? JSONSerialization.data(withJSONObject: jsonObject, options: [.prettyPrinted, .withoutEscapingSlashes])
} else {
pretty = try? JSONSerialization.data(withJSONObject: jsonObject, options: [.prettyPrinted])
}
guard let pretty = pretty else {
return nil
}
return String(data: pretty, encoding: .utf8)
}
}
And this is how the output of logNetworkResponse() is printed:
public func didReceive(_ result: Result<Moya.Response, MoyaError>, target: TargetType) {
var outputMessage: String?
if case .success(let response) = result {
// Attempt to parse the data for pretty printing only in QA Env
if printNetworkActivity {
outputMessage = logNetworkResponse(response.response, data: response.data, target: target)
}
} else {
outputMessage = logNetworkResponse(nil, data: nil, target: target)
}
output(message: outputMessage)
}
private func output(message: String?) {
if let message = message,
printNetworkActivity {
print(message)
}
}
I want the pretty printed output to be valid and without random additional characters that messes it up. Does anybody know what is this symbol 327\ and why is is sometimes inserted inside the texts?
I am struggling with Swift 3. I am getting (hexString) response from server in encrypted form and I am first converting it into Data.
Below is my method to converting hexString to in Data:
extension String {
func dataFromHexadecimalString() -> Data? {
var data = Data(capacity: characters.count / 2)
let regex = try! NSRegularExpression(pattern: "[0-9a-f]{1,2}", options: .caseInsensitive)
regex.enumerateMatches(in: self, options: [], range: NSMakeRange(0, characters.count)) { match, flags, stop in
let byteString = (self as NSString).substring(with: match!.range)
var num = UInt8(byteString, radix: 16)!
data.append(&num, count: 1)
}
guard data.count > 0 else {
return nil
}
return data
}
}
After that I am Decrypting the data using CryptoSwift framework. Here below is my method to decrypt the data :-
func getAllShops(data : [String : AnyObject]) {
AFWrapper.sharedInstance.requestPOSTURL(My_URL, params: data, headers: nil, success: {(json) in
// Key for AES
let key = "My_Key"
// Iv for AES
let iv = "My_IV"
//Hex String from Server Response
let str = json["encrypted"].string!
do {
//Converting Hex String to Data
let dataStr = str.dataFromHexadecimalString()
//Decrypt the Data
let decryptedData = try AES(key: key, iv: iv, blockMode: .CBC, padding: NoPadding()).decrypt(dataStr!)
//Getting json string Response
var jsonResponse = String(bytes: decryptedData, encoding: .utf8)!
/*let response = JSON(jsonResponse)
print(response)
let validJson = JSONSerialization.isValidJSONObject(response)//(JSONSerialization.JSONObjectWithData(jsonData, options:nil, error: &error) != nil)
print("Valid JSON: \(validJson)")*/
/*let data = jsonResponse.data(using: String.Encoding.utf8)
let jsonsdd = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! [String:Any]
print(jsonsdd)*/
}
catch {
print(error)
}
}, failure: {(Error) in
print(Error.localizedDescription)
})
}.
I am trying to convert that json String to in JSON object so that I can parse the data.
I tried with swiftyJSON and JSONSerialization in my code that part is commented. but not able to convert it.
I guess I am missing small thing that I don't know.
I created an extension on 'Dictionary' to help me parse JSON. The method below helps me do this:
func toJSONString() -> String? {
if let dict = self as? AnyObject {
if let data = try? JSONSerialization.data(withJSONObject: dict, options: JSONSerialization.WritingOptions(rawValue: 0)) {
if let json = String(data: data, encoding: String.Encoding.utf8) {
return json
}
}
}
return nil
}
The issue occurs on this line:
if let dict = self as? AnyObject {
I get a warning saying "Non-optional expression of type 'AnyObject' used in a check for optionals"
How do I go about solving this issue?
Simply remove the line that causes warning from your code and pass self as is for the JSONSerialization function. This should work without any issues:
extension Dictionary {
func toJSONString() -> String? {
if let data = try? JSONSerialization.data(withJSONObject: self, options: JSONSerialization.WritingOptions(rawValue: 0)) {
if let json = String(data: data, encoding: String.Encoding.utf8) {
return json
}
}
return nil
}
}
Your are unwrapping something that was already unwrapped. Take a look at this stackoverflow post
I have an NSDictionary object.
How do i get json String from this object?
var myNSDictObject ...
...
println(myNSDictObject.description)
This prints a pretty formatted string, with semicolons, newlines inserted etc.. it is not even proper json. So this does not work.
func generateJSONString(dictionary : NSDictionary) -> NSString? {
var error : NSError?
if let data = NSJSONSerialization.dataWithJSONObject(dictionary, options: nil, error: &error) {
return NSString(data: data, encoding: NSUTF8StringEncoding)
} else {
println("\(error?.localizedDescription)")
return nil
}
}
How do you convert an array to a JSON string in swift?
Basically I have a textfield with a button embedded in it.
When button is pressed, the textfield text is added unto the testArray.
Furthermore, I want to convert this array to a JSON string.
This is what I have tried:
func addButtonPressed() {
if goalsTextField.text == "" {
// Do nothing
} else {
testArray.append(goalsTextField.text)
goalsTableView.reloadData()
saveDatatoDictionary()
}
}
func saveDatatoDictionary() {
data = NSKeyedArchiver.archivedDataWithRootObject(testArray)
newData = NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions(), error: nil) as? NSData
string = NSString(data: newData!, encoding: NSUTF8StringEncoding)
println(string)
}
I would also like to return the JSON string using my savetoDictionart() method.
As it stands you're converting it to data, then attempting to convert the data to to an object as JSON (which fails, it's not JSON) and converting that to a string, basically you have a bunch of meaningless transformations.
As long as the array contains only JSON encodable values (string, number, dictionary, array, nil) you can just use NSJSONSerialization to do it.
Instead just do the array->data->string parts:
Swift 3/4
let array = [ "one", "two" ]
func json(from object:Any) -> String? {
guard let data = try? JSONSerialization.data(withJSONObject: object, options: []) else {
return nil
}
return String(data: data, encoding: String.Encoding.utf8)
}
print("\(json(from:array as Any))")
Original Answer
let array = [ "one", "two" ]
let data = NSJSONSerialization.dataWithJSONObject(array, options: nil, error: nil)
let string = NSString(data: data!, encoding: NSUTF8StringEncoding)
although you should probably not use forced unwrapping, it gives you the right starting point.
Swift 3.0 - 4.0 version
do {
//Convert to Data
let jsonData = try JSONSerialization.data(withJSONObject: dictionaryOrArray, options: JSONSerialization.WritingOptions.prettyPrinted)
//Convert back to string. Usually only do this for debugging
if let JSONString = String(data: jsonData, encoding: String.Encoding.utf8) {
print(JSONString)
}
//In production, you usually want to try and cast as the root data structure. Here we are casting as a dictionary. If the root object is an array cast as [Any].
var json = try JSONSerialization.jsonObject(with: jsonData, options: JSONSerialization.ReadingOptions.mutableContainers) as? [String: Any]
} catch {
print(error.description)
}
The JSONSerialization.WritingOptions.prettyPrinted option gives it to the eventual consumer in an easier to read format if they were to print it out in the debugger.
Reference: Apple Documentation
The JSONSerialization.ReadingOptions.mutableContainers option lets you mutate the returned array's and/or dictionaries.
Reference for all ReadingOptions: Apple Documentation
NOTE: Swift 4 has the ability to encode and decode your objects using a new protocol. Here is Apples Documentation, and a quick tutorial for a starting example.
If you're already using SwiftyJSON:
https://github.com/SwiftyJSON/SwiftyJSON
You can do this:
// this works with dictionaries too
let paramsDictionary = [
"title": "foo",
"description": "bar"
]
let paramsArray = [ "one", "two" ]
let paramsJSON = JSON(paramsArray)
let paramsString = paramsJSON.rawString(encoding: NSUTF8StringEncoding, options: nil)
SWIFT 3 UPDATE
let paramsJSON = JSON(paramsArray)
let paramsString = paramsJSON.rawString(String.Encoding.utf8, options: JSONSerialization.WritingOptions.prettyPrinted)!
JSON strings, which are good for transport, don't come up often because you can JSON encode an HTTP body. But one potential use-case for JSON stringify is Multipart Post, which AlamoFire nows supports.
How to convert array to json String in swift 2.3
var yourString : String = ""
do
{
if let postData : NSData = try NSJSONSerialization.dataWithJSONObject(yourArray, options: NSJSONWritingOptions.PrettyPrinted)
{
yourString = NSString(data: postData, encoding: NSUTF8StringEncoding)! as String
}
}
catch
{
print(error)
}
And now you can use yourSting as JSON string..
Swift 5
This generic extension will convert an array of objects to a JSON string from which it can either be:
saved to the App's Documents Directory (iOS/MacOS)
output directly to a file on the Desktop (MacOS)
.
extension JSONEncoder {
static func encode<T: Encodable>(from data: T) {
do {
let jsonEncoder = JSONEncoder()
jsonEncoder.outputFormatting = .prettyPrinted
let json = try jsonEncoder.encode(data)
let jsonString = String(data: json, encoding: .utf8)
// iOS/Mac: Save to the App's documents directory
saveToDocumentDirectory(jsonString)
// Mac: Output to file on the user's Desktop
saveToDesktop(jsonString)
} catch {
print(error.localizedDescription)
}
}
static private func saveToDocumentDirectory(_ jsonString: String?) {
guard let path = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
let fileURL = path.appendingPathComponent("Output.json")
do {
try jsonString?.write(to: fileURL, atomically: true, encoding: .utf8)
} catch {
print(error.localizedDescription)
}
}
static private func saveToDesktop(_ jsonString: String?) {
let homeURL = FileManager.default.homeDirectoryForCurrentUser
let desktopURL = homeURL.appendingPathComponent("Desktop")
let fileURL = desktopURL.appendingPathComponent("Output.json")
do {
try jsonString?.write(to: fileURL, atomically: true, encoding: .utf8)
} catch {
print(error.localizedDescription)
}
}
}
Example:
struct Person: Codable {
var name: String
var pets: [Pet]
}
struct Pet: Codable {
var type: String
}
extension Person {
static func sampleData() -> [Person] {
[
Person(name: "Adam", pets: []),
Person(name: "Jane", pets: [
Pet(type: "Cat")
]),
Person(name: "Robert", pets: [
Pet(type: "Cat"),
Pet(type: "Rabbit")
])
]
}
}
Usage:
JSONEncoder.encode(from: Person.sampleData())
Output:
This will create the following correctly formatted Output.json file:
[
{
"name" : "Adam",
"pets" : [
]
},
{
"name" : "Jane",
"pets" : [
{
"type" : "Cat"
}
]
},
{
"name" : "Robert",
"pets" : [
{
"type" : "Cat"
},
{
"type" : "Rabbit"
}
]
}
]
SWIFT 2.0
var tempJson : NSString = ""
do {
let arrJson = try NSJSONSerialization.dataWithJSONObject(arrInvitationList, options: NSJSONWritingOptions.PrettyPrinted)
let string = NSString(data: arrJson, encoding: NSUTF8StringEncoding)
tempJson = string! as NSString
}catch let error as NSError{
print(error.description)
}
NOTE:- use tempJson variable when you want to use.
extension Array where Element: Encodable {
func asArrayDictionary() throws -> [[String: Any]] {
var data: [[String: Any]] = []
for element in self {
data.append(try element.asDictionary())
}
return data
}
}
extension Encodable {
func asDictionary() throws -> [String: Any] {
let data = try JSONEncoder().encode(self)
guard let dictionary = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: Any] else {
throw NSError()
}
return dictionary
}
}
If you're using Codable protocols in your models these extensions might be helpful for getting dictionary representation (Swift 4)
Hint: To convert an NSArray containing JSON compatible objects to an NSData object containing a JSON document, use the appropriate method of NSJSONSerialization. JSONObjectWithData is not it.
Hint 2: You rarely want that data as a string; only for debugging purposes.
For Swift 4.2, that code still works fine
var mnemonic: [String] = ["abandon", "amount", "liar", "buyer"]
var myJsonString = ""
do {
let data = try JSONSerialization.data(withJSONObject:mnemonic, options: .prettyPrinted)
myJsonString = NSString(data: data, encoding: String.Encoding.utf8.rawValue) as! String
} catch {
print(error.localizedDescription)
}
return myJsonString
Swift 5
Make sure your object confirm Codable.
Swift's default variable types like Int, String, Double and ..., all are Codable that means we can convert theme to Data and vice versa.
For example, let's convert array of Int to String Base64
let array = [1, 2, 3]
let data = try? JSONEncoder().encode(array)
nsManagedObject.array = data?.base64EncodedString()
Make sure your NSManaged variable type is String in core data schema editor and custom class if your using custom class for core data objects.
let's convert back base64 string to array:
var getArray: [Int] {
guard let array = array else { return [] }
guard let data = Data(base64Encoded: array) else { return [] }
guard let val = try? JSONDecoder().decode([Int].self, from: data) else { return [] }
return val
}
Do not convert your own object to Base64 and store as String in CoreData and vice versa because we have something that named Relation in CoreData (databases).
For Swift 3.0 you have to use this:
var postString = ""
do {
let data = try JSONSerialization.data(withJSONObject: self.arrayNParcel, options: .prettyPrinted)
let string1:String = NSString(data: data, encoding: String.Encoding.utf8.rawValue) as! String
postString = "arrayData=\(string1)&user_id=\(userId)&markupSrcReport=\(markup)"
} catch {
print(error.localizedDescription)
}
request.httpBody = postString.data(using: .utf8)
100% working TESTED
You can try this.
func convertToJSONString(value: AnyObject) -> String? {
if JSONSerialization.isValidJSONObject(value) {
do{
let data = try JSONSerialization.data(withJSONObject: value, options: [])
if let string = NSString(data: data, encoding: String.Encoding.utf8.rawValue) {
return string as String
}
}catch{
}
}
return nil
}