Swift에서 JSON 문자열을 Object로 변환하는 간단하고 깨끗한 방법


83

나는 매우 간단한 JSON 문자열을 Swift에서 객체 유형으로 변환 할 수있는 날을 찾고 있지만 아무 소용이 없습니다.

다음은 웹 서비스 호출을위한 코드입니다.

func GetAllBusiness() {

        Alamofire.request(.GET, "http://MyWebService/").responseString { (request, response, string, error) in

                println(string)

        }
}

빠른 구조체 Business.swift가 있습니다.

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
  }
  ...
]

누군가가 이것을 통해 나를 인도한다면 기쁠 것입니다.

감사.

답변:


56

다음은 간단한 예제로 시작하는 방법에 대한 몇 가지 팁입니다.

다음과 같은 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    

[편집하다]

null을 제거하려면 다음과 같이 변경하십시오.

b.name = (json["name"] as AnyObject? as? String) ?? ""
b.id  =  (json["id"]  as AnyObject? as? Int) ?? 0 

참조 참조 Coalescing Operator(일명 ??)

문제를 해결하는 데 도움이되기를 바랍니다.


대박! 매력처럼 작동했습니다. 감사! 한 가지 작은 점은 JSON의 요소가 null이면 오류가 발생하는 것입니다. 다음과 같이 : b.name = json [ "name"] as AnyObject! as String name이 null 인 경우 어떻게 null을 허용하도록 조건을 추가 할 수 있습니까?
Hasan Nizamani 2014 년

String으로 캐스트하기 전에 AnyObject로 캐스트해야 할 필요성은 무엇입니까?
Bateramos 2015

@Bateramos 아무것도. AnyObject키로 선택 사항 을 얻 습니다 nil. String으로 다운 캐스팅하기 전에 . 이런 이유로 당신이 할 수있는 나는 사용하여 incapsualte하기 위해 !또는 내 경우 ?holdplace와??
맥심 Shoustin

객체 var b:Business = Business()외부 루프 를 생성하면 각 목록 요소에 동일한 데이터가 표시 될 수 있습니다.
Patriks 2015

50

신속한 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

2
미래 각주 : 대신은 do-catch, try?에서 전무를 반환과 같은 결과를 줄 것이다, 여기에 사용할 수 있습니다 catch.
Okhan Okbay 2017-06-27

... 그리고이 변환 후 정확히 하나가 매개 변수에 액세스하는 방법은 무엇입니까?
Starwave

관심있는 다른 사람 : let jsonObjectAsNSDictionary = responseString? .toJSON () as! [String : AnyObject] print (jsonObjectAsNSDictionary [ "permissions"]! [ "canaddeditowncomment"])
Starwave

1
신속한 구문을 수정하십시오 ... 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) } }
Yasir Ali

27

간단한 문자열 확장으로 충분합니다.

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";
}
*/

15

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)

자세한 배경 정보는 이 훌륭한 가이드를 확인하십시오 .


이것의 단점은 구조체를 추적해야한다는 것이고, 매개 변수가 30 개 이상일 경우 관리가 큰 번거 로움이 될 것입니다.
Starwave

@Starwave : 이것이 문제를 해결하는지 확실하지 않지만 데이터를 디코딩하는 데 사용하는 구조체에 관심있는 필드 만 포함하면됩니다. 예를 들어 JSON 형식이 [{ "id": 1, "name :"A ","location ":"Warsaw "},] 인 경우에도 동일한 비즈니스 구조를 사용하여 디코딩 할 수 있습니다. 위치 필드는 다음과 같습니다. 무시.
Noyer282

빌어 먹을, 나는 그것을 생각하지 않았다. 그러나 여기에 parsedData는 무엇인가? NSDictionary?
Starwave

@Starwave : 원래 질문에서와 마찬가지로 구조체 배열입니다.
Noyer282

9

대한 스위프트 4

@ Passkit 논리를 사용했지만 Swift 4에 따라 업데이트해야했습니다.


Step.1 String Class 확장 생성

import UIKit


extension String
    {
        var parseJSONString: AnyObject?
        {
            let data = self.data(using: String.Encoding.utf8, allowLossyConversion: false)

            if let jsonData = data
            {
                // Will return an object or nil if JSON decoding fails
                do
                {
                    let message = try JSONSerialization.jsonObject(with: jsonData, options:.mutableContainers)
                    if let jsonResult = message as? NSMutableArray
                    {
                        print(jsonResult)

                        return jsonResult //Will return the json array 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
            }
        }
    }

Step.2 이것은 내 뷰 컨트롤러에서 사용한 방법입니다.

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

 //Convert jsonString to jsonArray

let json: AnyObject? = jsonString.parseJSONString
print("Parsed JSON: \(json!)")
print("json[2]: \(json![2])")

모든 크레딧은 원래 사용자에게 전달됩니다. 방금 최신 swift 버전으로 업데이트했습니다.


7

저는 Swift에서 json 데이터와 역 직렬화 작업을 쉽게하는 라이브러리를 작성했습니다. 여기에서 얻을 수 있습니다 : https://github.com/isair/JSONHelper

편집 : 내 라이브러리를 업데이트했습니다. 이제 다음과 같이 할 수 있습니다.

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을 사용하는 대신 .response를 사용하여 응답 객체를 가져옵니다. 그런 다음 코드를 다음과 같이 변경하십시오.

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 저장소에서 전체 문서를 찾을 수 있습니다. 즐기세요!


감사! 하지만 제가 작업하고있는 대학 프로젝트이기 때문에 맞춤형 방식을 찾고 있었으며, 제가 API를 사용하고 있다는 사실을 감독관은별로 좋아하지 않을 것입니다.
Hasan Nizamani 2014 년

내 개인 프로젝트에서 라이브러리를 사용합니다. 감사!!
Hasan Nizamani 2014 년

어떤 식 으로든 도움을 줄 수있어서 다행입니다. 프로젝트에 행운을 빕니다! ^^
isair

6

들어 스위프트 4 , 내가 사용이 확장 쓴 Codable의 프로토콜 :

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)

4

들어 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")
  }
}

여기에 카테고리 클래스가 있습니다.

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

IMO, 이것은 지금까지 가장 우아한 솔루션입니다.


2
let jsonString = "{\"id\":123,\"Name\":\"Munish\"}"

문자열을 NSData로 변환

 var data: NSData =jsonString.dataUsingEncoding(NSUTF8StringEncoding)!

 var error: NSError?

NSData를 AnyObject로 변환

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

2

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

2

SWIFT4 -JSON 문자열을 Struct로 디코딩하는 쉽고 우아한 방법.

첫 번째 단계 -.utf8 인코딩을 사용하여 문자열을 데이터로 인코딩합니다.

데이터를 YourDataStruct로 디코딩하는 것보다 .

struct YourDataStruct: Codable {

let type, id: String

init(_ json: String, using encoding: String.Encoding = .utf8) throws {
    guard let data = json.data(using: encoding) else {
        throw NSError(domain: "JSONDecoding", code: 0, userInfo: nil)
    }
    try self.init(data: data)
}

init(data: Data) throws {
    self = try JSONDecoder().decode(YourDataStruct.self, from: data)
}                                                                      
}

do { let successResponse = try WSDeleteDialogsResponse(response) }
} catch {}

1

swift.quicktype.io 를 사용 JSON하여 struct또는class . 코드를 생성하기 위해 신속한 버전을 언급 할 수도 있습니다.

예제 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
    }
}

1

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

0

다음은 작업을 더 간단하고 쉽게 만드는 샘플입니다. 내 데이터베이스의 내 문자열 데이터는 다음과 같은 JSON 파일입니다.

[{"stype":"noun","sdsc":"careless disregard for consequences","swds":"disregard, freedom, impulse, licentiousness, recklessness, spontaneity, thoughtlessness, uninhibitedness, unrestraint, wantonness, wildness","anwds":"restraint, self-restraint"},{"stype":"verb","sdsc":"leave behind, relinquish","swds":"abdicate, back out, bail out, bow out, chicken out, cop out, cut loose, desert, discard, discontinue, ditch, drop, drop out, duck, dump, dust, flake out, fly the coop, give up the ship, kiss goodbye, leave, leg it, let go, opt out, pull out, quit, run out on, screw, ship out, stop, storm out, surrender, take a powder, take a walk, throw over, vacate, walk out on, wash hands of, withdraw, yield","anwds":"adopt, advance, allow, assert, begin, cherish, come, continue, defend, favor, go, hold, keep, maintain, persevere, pursue, remain, retain, start, stay, support, uphold"},{"stype":"verb","sdsc":"leave in troubled state","swds":"back out, desert, disown, forsake, jilt, leave, leave behind, quit, reject, renounce, throw over, walk out on","anwds":"adopt, allow, approve, assert, cherish, come, continue, defend, favor, keep, pursue, retain, stay, support, uphold"}]

이 JSON 문자열 데이터를로드하려면 다음 간단한 단계를 따르십시오. 먼저 다음과 같이 내 MoreData 개체에 대한 클래스를 만듭니다.

class  MoreData {
public private(set) var stype : String
public private(set) var sdsc : String
public private(set) var swds : String
public private(set) var anwds : String

init( stype : String, sdsc : String, swds : String, anwds : String) {

    self.stype = stype
    self.sdsc = sdsc
    self.swds = swds
    self.anwds = anwds
}}

둘째, 다음과 같이 JSON 문자열에 대한 문자열 확장을 만듭니다.

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

셋째, 내 Srevices 클래스를 생성하여 다음과 같이 내 문자열 데이터를 처리합니다.

class Services {
static let instance: Services = Services()

func loadMoreDataByString(byString: String) -> [MoreData]{
    var  myVariable = [MoreData]()

    guard let ListOf = byString.toJSON() as? [[String: AnyObject]] else { return  [] }

    for object in ListOf {
        let stype  = object["stype"] as? String ?? ""
        let sdsc  = object["sdsc"] as? String ?? ""
         let swds  = object["swds"] as? String ?? ""
        let anwds  = object["anwds"] as? String ?? ""

        let myMoreData = MoreData(stype : stype, sdsc : sdsc, swds : swds, anwds : anwds)
        myVariable.append(myMoreData)
    }
    return myVariable
}}

마지막으로 뷰 컨트롤러에서이 함수를 호출하여 다음과 같이 테이블 뷰에 데이터를로드합니다.

    func handlingJsonStringData(){
    moreData.removeAll(keepingCapacity: false)
    moreData =  Services.instance.loadMoreDataByString(byString: jsonString)
    print(self.moreData.count)
    tableView.reloadData()
}

0

누군가를 도울 수 있습니다. 비슷한 예.

이것은 우리입니다 Codable바인딩 데이터 클래스입니다. SwiftyJsonAccelerator를 사용 하여이 클래스를 쉽게 만들 수 있습니다.

 class ModelPushNotificationFilesFile: Codable {

  enum CodingKeys: String, CodingKey {
    case url
    case id
    case fileExtension = "file_extension"
    case name
  }

  var url: String?
  var id: Int?
  var fileExtension: String?
  var name: String?

  init (url: String?, id: Int?, fileExtension: String?, name: String?) {
    self.url = url
    self.id = id
    self.fileExtension = fileExtension
    self.name = name
  }

  required init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    url = try container.decodeIfPresent(String.self, forKey: .url)
    id = try container.decodeIfPresent(Int.self, forKey: .id)
    fileExtension = try container.decodeIfPresent(String.self, forKey: .fileExtension)
    name = try container.decodeIfPresent(String.self, forKey: .name)
  }

}

이것은 Json String입니다.

    let jsonString = "[{\"name\":\"\",\"file_extension\":\"\",\"id\":10684,\"url\":\"https:\\/\\/homepages.cae.wisc.edu\\/~ece533\\/images\\/tulips.png\"},

{\"name\":\"\",\"file_extension\":\"\",\"id\":10684,\"url\":\"https:\\/\\/homepages.cae.wisc.edu\\/~ece533\\/images\\/arctichare.png\"},

{\"name\":\"\",\"file_extension\":\"\",\"id\":10684,\"url\":\"https:\\/\\/homepages.cae.wisc.edu\\/~ece533\\/images\\/serrano.png\"},

{\"name\":\"\",\"file_extension\":\"\",\"id\":10684,\"url\":\"https:\\/\\/homepages.cae.wisc.edu\\/~ece533\\/images\\/peppers.png\"},

{\"name\":\"\",\"file_extension\":\"\",\"id\":10684,\"url\":\"https:\\/\\/homepages.cae.wisc.edu\\/~ece533\\/images\\/pool.png\"}]"

여기서 우리는 신속한 객체로 변환합니다.

   let jsonData = Data(jsonString.utf8)

        let decoder = JSONDecoder()

        do {
            let fileArray = try decoder.decode([ModelPushNotificationFilesFile].self, from: jsonData)
            print(fileArray)
            print(fileArray[0].url)
        } catch {
            print(error.localizedDescription)
        }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.