在Swift中将数组转换为JSON字符串

78

在Swift中如何将数组转换为JSON字符串? 基本上,我有一个带有内嵌按钮的文本框。 当按下按钮时,文本框文本被添加到testArray中。 此外,我想将此数组转换为JSON字符串。

这是我尝试过的:

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)
}

我还想使用我的savetoDictionart()方法返回JSON字符串。

12个回答

143

目前你正在将数据转换为对象,然后尝试将该对象作为JSON转换为字符串(失败了,它不是JSON),实际上你进行了许多无意义的转换。

只要数组只包含JSON可编码值(字符串、数字、字典、数组、nil),你可以直接使用NSJSONSerialization进行转换。

相反,只需执行数组->数据->字符串部分:

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)

尽管你可能不应该使用强制解包,但它可以给你一个正确的起点。

使用上面的片段,我获得了"[\"one\",\"two\"]",现在该如何将其转换为字符串数组?谢谢。 - sweepez
@sweepez 我认为你看到的只是调试器的一个副作用。 - David Berry

57

Swift 3.0 - 4.0 版本

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)
}

JSONSerialization.WritingOptions.prettyPrinted选项可以让最终的使用者以更易于阅读的格式在调试器中打印出来。

参考文献:苹果官方文档

JSONSerialization.ReadingOptions.mutableContainers选项允许您修改返回的数组和/或字典。

所有ReadingOptions的参考文献:苹果官方文档

注意:Swift 4有一种新的协议,可以对对象进行编码和解码。这里是苹果的文档和一个入门教程


1
请注意,您可以让Swift为某些参数推断类型 - 例如 let jsonData = try JSONSerialization.data(withJSONObject: dictionaryOrArray, options: .prettyPrinted) - String(data: jsonData, encoding: .utf8)。如果您将其转换为本机Swift集合,则.mutableContainers选项是不必要的。 - Hamish

22

如果你已经在使用SwiftyJSON:

https://github.com/SwiftyJSON/SwiftyJSON

你可以这样做:

// 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更新

 let paramsJSON = JSON(paramsArray)
 let paramsString = paramsJSON.rawString(String.Encoding.utf8, options: JSONSerialization.WritingOptions.prettyPrinted)!

JSON字符串通常用于传输,因为您可以将HTTP主体进行JSON编码,所以不经常遇到JSON字符串。但是,JSON stringify 的一个潜在用例是多部分提交(post),现在AlamoFire已支持该功能。


SwiftyJSON是一种比在Swift中处理NSString更为优雅和快捷的解决方案。但我建议使用if let str = json.rawString() ...来检测是否出现问题并返回nil。 - Sebastian
使用上面的 SwiftyJSON 代码片段,我得到了 "[\"one\",\"two\"]",现在我该如何将其转换回原始的字符串数组呢?谢谢。 - sweepez

6

Swift 5

这个泛型的extension将会把一个对象的array转换成一个JSON string,然后可以将其保存到应用程序的文档目录(iOS/MacOS),或是直接输出到桌面上的文件中(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)
        }
    }
}

例子:

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")
            ])
        ]
    }
}

用法:

JSONEncoder.encode(from: Person.sampleData())

输出:

这将创建以下正确格式化的Output.json文件:

[
  {
    "name" : "Adam",
    "pets" : [

    ]
  },
  {
    "name" : "Jane",
    "pets" : [
      {
        "type" : "Cat"
      }
    ]
  },
  {
    "name" : "Robert",
    "pets" : [
      {
        "type" : "Cat"
      },
      {
        "type" : "Rabbit"
      }
    ]
  }
]

6

如何在Swift 2.3中将数组转换为JSON字符串

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)
}

现在您可以将yourString用作JSON字符串。

5

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)
}

注意:当您想使用时,请使用tempJson变量。


5
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
        }
}

如果您在模型中使用Codable协议,以下扩展功能可能有助于获取字典表示形式(Swift 4


2

提示:要将包含JSON兼容对象的NSArray转换为包含JSON文档的NSData对象,请使用NSJSONSerialization的适当方法。JSONObjectWithData不是它。

提示2:您很少需要将数据作为字符串;仅用于调试目的。


我试图先将'testArray'转换为NSData格式,然后再转换为json。谢谢您的回复。 - DrPatience

2

Swift 5

请确保您的对象符合 Codable

Swift 的默认变量类型,如 Int、String、Double 等,都是 Codable,这意味着我们可以将它们转换为 Data,反之亦然。

例如,让我们将 Int 数组转换为 String Base64。

let array = [1, 2, 3]
let data = try? JSONEncoder().encode(array)
nsManagedObject.array = data?.base64EncodedString()

请确保在core data模式编辑器和自定义类中,NSManaged变量的类型为String,如果您正在为core data对象使用自定义类。

让我们将base64字符串转换回数组:

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
}

不要将自己的对象转换为Base64并存储为字符串在CoreData中,反之亦然,因为在CoreData(数据库)中有名为Relation的东西。

你如何将其存储到扩展中,以供与coredata无关的其他转换使用? - ElKePoN

2
对于Swift 4.2,那段代码仍然可以正常工作。
 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

我的Json字符串能否再次编码为数组字符串? - Ade Dyas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接