Простой и чистый способ преобразования строки JSON в объект в Swift
Я искал в течение нескольких дней, чтобы преобразовать довольно простую строку JSON в тип объекта в Swift, но безрезультатно.
вот код для вызова веб-службы:
func GetAllBusiness() {
Alamofire.request(.GET, "http://MyWebService/").responseString { (request, response, string, error) in
println(string)
}
}
у меня есть бизнес swift struct.Свифт:
struct Business {
var Id : Int = 0
var Name = ""
var Latitude = ""
var Longitude = ""
var Address = ""
}
вот мой тестовый сервис развернуто:
[
{
"Id": 1,
"Name": "A",
"Latitude": "-35.243256",
"Longitude": "149.110701",
"Address": null
},
{
"Id": 2,
"Name": "B",
"Latitude": "-35.240592",
"Longitude": "149.104843",
"Address": null
}
...
]
было бы приятно, если кто-то наставит меня через это.
спасибо.
12 ответов:
вот несколько советов, как начать с простого примера.
считайте, что у вас есть следующая строка массива JSON (похожая на вашу), например:
var list:Array<Business> = [] // left only 2 fields for demo struct Business { var id : Int = 0 var name = "" } var jsonStringAsArray = "[\n" + "{\n" + "\"id\":72,\n" + "\"name\":\"Batata Cremosa\",\n" + "},\n" + "{\n" + "\"id\":183,\n" + "\"name\":\"Caldeirada de Peixes\",\n" + "},\n" + "{\n" + "\"id\":76,\n" + "\"name\":\"Batata com Cebola e Ervas\",\n" + "},\n" + "{\n" + "\"id\":56,\n" + "\"name\":\"Arroz de forma\",\n" + "}]" // convert String to NSData var data: NSData = jsonStringAsArray.dataUsingEncoding(NSUTF8StringEncoding)! var error: NSError? // convert NSData to 'AnyObject' let anyObj: AnyObject? = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &error) println("Error: \(error)") // convert 'AnyObject' to Array<Business> list = self.parseJson(anyObj!) //=============== func parseJson(anyObj:AnyObject) -> Array<Business>{ var list:Array<Business> = [] if anyObj is Array<AnyObject> { var b:Business = Business() for json in anyObj as Array<AnyObject>{ b.name = (json["name"] as AnyObject? as? String) ?? "" // to get rid of null b.id = (json["id"] as AnyObject? as? Int) ?? 0 list.append(b) }// for } // if return list }//func
[EDIT]
чтобы избавиться от null изменен на:
b.name = (json["name"] as AnyObject? as? String) ?? "" b.id = (json["id"] as AnyObject? as? Int) ?? 0
см. также ссылки Коалесцирующий Оператор (он же
??
)надеюсь, что это поможет Вам разобраться,
как простое расширение строки должно быть достаточно:
extension String { var parseJSONString: AnyObject? { let data = self.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) if let jsonData = data { // Will return an object or nil if JSON decoding fails return NSJSONSerialization.JSONObjectWithData(jsonData, options: NSJSONReadingOptions.MutableContainers, error: nil) } else { // Lossless conversion of the string was not possible return nil } } }
затем:
var jsonString = "[\n" + "{\n" + "\"id\":72,\n" + "\"name\":\"Batata Cremosa\",\n" + "},\n" + "{\n" + "\"id\":183,\n" + "\"name\":\"Caldeirada de Peixes\",\n" + "},\n" + "{\n" + "\"id\":76,\n" + "\"name\":\"Batata com Cebola e Ervas\",\n" + "},\n" + "{\n" + "\"id\":56,\n" + "\"name\":\"Arroz de forma\",\n" + "}]" let json: AnyObject? = jsonString.parseJSONString println("Parsed JSON: \(json!)") println("json[3]: \(json![3])") /* Output: Parsed JSON: ( { id = 72; name = "Batata Cremosa"; }, { id = 183; name = "Caldeirada de Peixes"; }, { id = 76; name = "Batata com Cebola e Ervas"; }, { id = 56; name = "Arroz de forma"; } ) json[3]: { id = 56; name = "Arroz de forma"; } */
для swift 3/4
extension String { func toJSON(): Any? { guard let data = self.data(using: .utf8, allowLossyConversion: false) else { return nil } return try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) } }
Пример Использования:
let dict = myString.toJSON() as? [String:AnyObject] // can be any type here
Я написал библиотеку, которая делает работу с данными json и десериализацию ветром в Swift. Вы можете получить его здесь: https://github.com/isair/JSONHelper
Edit: я обновил свою библиотеку, теперь вы можете сделать это только с этим:
class Business: Deserializable { var id: Int? var name = "N/A" // This one has a default value. required init(data: [String: AnyObject]) { id <-- data["id"] name <-- data["name"] } } var businesses: [Business]() Alamofire.request(.GET, "http://MyWebService/").responseString { (request, response, string, error) in businesses <-- string }
Ответ:
во-первых, вместо использования .responseString, use .ответ, чтобы получить объект ответа. Затем измените свой код на:
func getAllBusinesses() { Alamofire.request(.GET, "http://MyWebService/").response { (request, response, data, error) in var businesses: [Business]? businesses <-- data if businesses == nil { // Data was not structured as expected and deserialization failed, do something. } else { // Do something with your businesses array. } } }
и вам нужно сделать Бизнес-класс такой:
class Business: Deserializable { var id: Int? var name = "N/A" // This one has a default value. required init(data: [String: AnyObject]) { id <-- data["id"] name <-- data["name"] } }
вы можете найти полную документацию по моему РЕПО GitHub. Получайте удовольствие!
на Swift 2.2
я использовал @Passkitлогика, но я должен был обновить в соответствии с Swift 2
на
iOS 10
&Swift 3
, используя Alamofire & блеск:Alamofire.request("http://localhost:8080/category/en").responseJSON { response in if let data = response.data { if let categories = [Category].from(data: response.data) { self.categories = categories self.categoryCollectionView.reloadData() } else { print("Casting error") } } else { print("Data is null") } }
а вот категория class
import Gloss struct Category: Decodable { let categoryId: Int? let name: String? let image: String? init?(json: JSON) { self.categoryId = "categoryId" <~~ json self.name = "name" <~~ json self.image = "image" <~~ json } }
ИМО, это, безусловно, самое элегантное решение.
Swift 4 разбирает JSON гораздо более элегантно. Просто примите кодируемый протокол для своей структуры в соответствии с этим упрощенным примером:
struct Business: Codable { let id: Int let name: String }
чтобы проанализировать массив JSON, вы сообщаете декодеру, какие объекты массива данных являются
let parsedData = decoder.decode([Business].self, from: data)
вот полный рабочий пример:
import Foundation struct Business: Codable { let id: Int let name: String } // Generating the example JSON data: let originalObjects = [Business(id: 0, name: "A"), Business(id: 1, name: "B")] let encoder = JSONEncoder() let data = try! encoder.encode(originalObjects) // Parsing the data: let decoder = JSONDecoder() let parsedData = try! decoder.decode([Business].self, from: data)
для получения дополнительной информации, проверьте это отличное руководство.
let jsonString = "{\"id\":123,\"Name\":\"Munish\"}"
преобразовать строку в NSData
var data: NSData =jsonString.dataUsingEncoding(NSUTF8StringEncoding)! var error: NSError?
преобразовать формат NSData, чтобы какой-либо объект
var jsonObject: AnyObject? = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.allZeros, error: &error) println("Error: \(error)") let id = (jsonObject as! NSDictionary)["id"] as! Int let name = (jsonObject as! NSDictionary)["name"] as! String println("Id: \(id)") println("Name: \(name)")
Мне нравится ответ RDC, но зачем ограничивать JSON, чтобы иметь только массивы на верхнем уровне? Мне нужно было разрешить словарь на верхнем уровне, поэтому я изменил его таким образом:
extension String { var parseJSONString: AnyObject? { let data = self.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) if let jsonData = data { // Will return an object or nil if JSON decoding fails do { let message = try NSJSONSerialization.JSONObjectWithData(jsonData, options:.MutableContainers) if let jsonResult = message as? NSMutableArray { return jsonResult //Will return the json array output } else if let jsonResult = message as? NSMutableDictionary { return jsonResult //Will return the json dictionary output } else { return nil } } catch let error as NSError { print("An error occurred: \(error)") return nil } } else { // Lossless conversion of the string was not possible return nil } }
вы можете использовать swift.quicktype.io для преобразования
JSON
илиstruct
илиclass
. Даже вы можете упомянуть версию swift для генерации кода.пример JSON:
{ "message": "Hello, World!" }
сгенерированный код:
import Foundation typealias Sample = OtherSample struct OtherSample: Codable { let message: String } // Serialization extensions extension OtherSample { static func from(json: String, using encoding: String.Encoding = .utf8) -> OtherSample? { guard let data = json.data(using: encoding) else { return nil } return OtherSample.from(data: data) } static func from(data: Data) -> OtherSample? { let decoder = JSONDecoder() return try? decoder.decode(OtherSample.self, from: data) } var jsonData: Data? { let encoder = JSONEncoder() return try? encoder.encode(self) } var jsonString: String? { guard let data = self.jsonData else { return nil } return String(data: data, encoding: .utf8) } } extension OtherSample { enum CodingKeys: String, CodingKey { case message } }
С помощью SwiftyJSON библиотека, вы могли бы сделать это как
if let path : String = Bundle.main.path(forResource: "tiles", ofType: "json") { if let data = NSData(contentsOfFile: path) { let optData = try? JSON(data: data as Data) guard let json = optData else { return } for (_, object) in json { let name = object["name"].stringValue print(name) } } }
на Swift 4, Я написал это расширение с помощью возможностью протокол:
struct Business: Codable { var id: Int var name: String } extension String { func parse<D>(to type: D.Type) -> D? where D: Decodable { let data: Data = self.data(using: .utf8)! let decoder = JSONDecoder() do { let _object = try decoder.decode(type, from: data) return _object } catch { return nil } } } var jsonString = "[\n" + "{\n" + "\"id\":72,\n" + "\"name\":\"Batata Cremosa\",\n" + "},\n" + "{\n" + "\"id\":183,\n" + "\"name\":\"Caldeirada de Peixes\",\n" + "},\n" + "{\n" + "\"id\":76,\n" + "\"name\":\"Batata com Cebola e Ervas\",\n" + "},\n" + "{\n" + "\"id\":56,\n" + "\"name\":\"Arroz de forma\",\n" + "}]" let businesses = jsonString.parse(to: [Business].self)