Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converting JSON to array in Swift 2

I need to build Arrays for a Grouped UITableView, with a Title and Detail line in each table cell. I've got my json output from the server putting it in the right shape to iterate through the UITableViewDataSource methods. But what's the simplest way to convert these to a readable array that those UITableView functions can reference?

The headings array is for the Group headings, so it's just a one-dimensional array. I can iterate that. The titles and details arrays are both two dimensional. I can't figure out how to do that in Swift.

"headings":["Tuesday, August 16, 2016","Wednesday, August 17, 2016","Thursday, August 18, 2016","Friday, August 19, 2016","Saturday, August 20, 2016","Sunday, August 21, 2016","Monday, August 22, 2016","Tuesday, August 23, 2016","Wednesday, August 24, 2016","Thursday, August 25, 2016","Friday, August 26, 2016","Saturday, August 27, 2016","Sunday, August 28, 2016","Monday, August 29, 2016","Tuesday, August 30, 2016","Wednesday, August 31, 2016","Thursday, September 1, 2016","Friday, September 2, 2016","Saturday, September 3, 2016","Sunday, September 4, 2016","Monday, September 5, 2016","Tuesday, September 6, 2016","Wednesday, September 7, 2016","Thursday, September 8, 2016","Friday, September 9, 2016","Saturday, September 10, 2016","Sunday, September 11, 2016","Monday, September 12, 2016","Tuesday, September 13, 2016","Wednesday, September 14, 2016","Thursday, September 15, 2016","Friday, September 16, 2016"],

"titles":[["Joe Johnson"],["Joe Johnson"],["Sandy Primmell","Joe Johnson"],["Joe Johnson"],["Joe Johnson"],["Joe Johnson"],["Joe Johnson"],["Sandy Primmell","Joe Johnson"],["Joe Johnson","Joe Johnson"],["Sandy Primmell","Joe Johnson"],["Mark Greene","Joe Johnson"],["Joe Johnson"],["Joe Johnson"],["Joe Johnson"],["Joe Johnson"],["Sandy Primmell","Joe Johnson"],["Joe Johnson"],["Sandy Primmell","Joe Johnson"],["Mark Greene","Joe Johnson"],["Joe Johnson"],["Joe Johnson"],["Joe Johnson"],["Joe Johnson"],["Joe Johnson"],["Joe Johnson"],["Joe Johnson"],["Joe Johnson"],["Joe Johnson"],["Joe Johnson"],["Joe Johnson"],["Joe Johnson"],["Joe Johnson"]],

"details":[["OFF"],["OFF"],["Gregory","OFF"],["Gregory"],["OFF"],["OFF"],["OFF"],["Weekday Rounders","OFF"],["Weekday Rounders","Night Owls"],["Gregory","OFF"],["Gregory","OFF"],["OFF"],["OFF"],["OFF"],["Gregory"],["Gregory","OFF"],["Gregory"],["Gregory","OFF"],["Gregory","OFF"],["OFF"],["OFF"],["OFF"],["OFF"],["OFF"],["OFF"],["OFF"],["OFF"],["OFF"],["OFF"],["OFF"],["OFF"],["OFF"]]

UPDATE

Here's my Alamofire async function that grabs the data:

manager.request(.POST, getRouter(), parameters:["dev": 1, "app_action": "schedule", "type":getScheduleType(), "days_off":getScheduleDaysOff(), "period":getSchedulePeriod(), "begin_date":getScheduleBeginDate(), "end_date":getScheduleEndDate()])
        .responseString {response in
            print(response)
            var json = JSON(response.result.value!);
// what I'm missing
   }
like image 205
Works for a Living Avatar asked Aug 16 '16 12:08

Works for a Living


3 Answers

You can use this function:

func convertStringToDictionary(text: String) -> [String:AnyObject]? {
    if let data = text.dataUsingEncodi‌​ng(NSUTF8StringEncodi‌​ng) {
        do {
            return try NSJSONSerialization.JSONObjectWithData(data, options: []) as? [String:AnyObject]
        } catch let error as NSError {
            print(error)
        }
    }
    return nil
}

and then you can read the array like this:

if let dict = convertStringToDictionary(jsonText) {
    let array = dict["headings"] as? [String]
}
like image 181
Marco Santarossa Avatar answered Oct 25 '22 02:10

Marco Santarossa


Alternatively, You can use JSON parsing libraries like Argo or SwiftyJSON, which were created to simplify the JSON parsing. They are both well tested and will handle edge cases for you, like missing parameters in the JSON responses etc.

An example using Argo:

Assuming the JSON response has this format (from Twitter API)

{
  "users": [
    {
      "id": 2960784075,
      "id_str": "2960784075",
      ...
    }
}

1- Create a Swift class to represent the response

Note that Response is a class that contains an array of User which is another class not shown here, but you get the point.

struct Response: Decodable {
    let users: [User]
    let next_cursor_str: String

    static func decode(j: JSON) -> Decoded<Response> {
        return curry(Response.init)
            <^> j <|| "users"
            <*> j <| "next_cursor_str"
    }
}

2- Parse the JSON

//Convert json String to foundation object
let json: AnyObject? = try? NSJSONSerialization.JSONObjectWithData(data, options: [])

//Check for nil    
if let j: AnyObject = json {
  //Map the foundation object to Response object
  let response: Response? = decode(j)
}

An example using Swifty

As explained in the official documentation:

1- Convert JSON string to SwiftyJSON object

if let dataFromString = jsonString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) {
    let json = JSON(data: dataFromString)
}

2- Access specific element

If data is an array then use the index

//Getting a double from a JSON Array
let name = json[0].double

If data is a dictionary then use the key

//Getting a string from a JSON Dictionary
let name = json["name"].stringValue

2'- Loop over the elements

Array

//If json is .Array
//The `index` is 0..<json.count's string value
for (index,subJson):(String, JSON) in json {
    //Do something you want
}

Dictionary

//If json is .Dictionary
for (key,subJson):(String, JSON) in json {
   //Do something you want
}
like image 44
Ahmad Baracat Avatar answered Oct 25 '22 02:10

Ahmad Baracat


I would suggest using AlamofireObjectMapper. The library lets you you map objects from json easily and if combined with Alamofire can cast and return your object on the server response. The object mapping itself should look like this in your case

class CustomResponseClass: Mappable {
    var headings: [String]?

    required init?(_ map: Map){

    }

    func mapping(map: Map) {
        headings <- map["headings"]
   }
}

This way you decouple the logic of mapping and parsing json from your tableViewController.

AlamofireObjectMapper

like image 39
Bashta Avatar answered Oct 25 '22 02:10

Bashta