Richard Downs Richard Downs - 1 month ago 11
Swift Question

How to unpack an array from php into Swift via JSON

I am retrieving an

Array
into Swift from PHP that contains the values from a couple of SQL queries.

The array is sent for, received and printed in Swift by following code:

let task = URLSession.shared.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in
DispatchQueue.main.async
{

let json = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String:AnyObject]

print (json)
}


The array contains
userDetails
and
Communities
and its output in Xcode (via printed debug) looks like the following:

Optional(["userDetails": {
id = 2;
"user_email" = "radowns82@gmail.com";
"user_name" = "<null>";
}, "communities": <__NSArrayI 0x60000002f500>(
{
name = Gallelio;
},
{
name = GallelioPart2;
}
)
])
Optional(["userDetails": {
id = 30;
"user_email" = "sam.bawdry@gmail.com";
"user_name" = "Samuel Bawdry";
}, "communities": <__NSArrayI 0x60800026e180>(
{
name = TesetTester;
},
{
name = Westbrook2;
},
{
name = WinnersOnly;
},
{
name = OneTwoThree;
},
{
name = WhoopdeWhoop;
}
)
])


How do I now unpack the contents of "communities" so I can display its contents in a
UITableVIew
- I have the
UITableView
already set up with and working with 'dummy data'.

This is the full Swift Script:

import UIKit

protocol UsernameSentDelegate {
func userLoggedIn(data: String)
}

class LoginViewController: UIViewController {

var delegate: UsernameSentDelegate? = nil

@IBOutlet weak var userEmailTextField: UITextField!
@IBOutlet weak var userPasswordTextField: UITextField!
@IBOutlet weak var displayUserName: UILabel!
var communitiesArray = [String]()


@IBAction func loginButtonTapped(_ sender: AnyObject)
{

let userEmail = userEmailTextField.text;
let userPassword = userPasswordTextField.text;

if (userPassword!.isEmpty || userEmail!.isEmpty) { return; }

// send user data to server side


let myUrl = URL(string: "http://www.quasisquest.uk/KeepScore/userLogin.php");

var request = URLRequest(url:myUrl!);

request.httpMethod = "POST";

let postString = "email=\(userEmail!)&password=\(userPassword!)";

request.httpBody = postString.data(using: String.Encoding.utf8);

let task = URLSession.shared.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in
DispatchQueue.main.async
{


if(error != nil)
{

//Display an alert message
let myAlert = UIAlertController(title: "Alert", message: error!.localizedDescription, preferredStyle: UIAlertControllerStyle.alert);
let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler:nil)
myAlert.addAction(okAction);
self.present(myAlert, animated: true, completion: nil)
return
}

do {

let json = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String:AnyObject]

if let arr = json?["communities"] as? [String:String] {
self.communitiesArray = arr.map { $0["name"] }
}


// retrieve login details and check to see if all ok

if let parseJSON = json {

let returnValue = parseJSON["status"] as? String

if(returnValue != "error")
{

self.delegate?.userLoggedIn(data: userEmail! )

UserDefaults.set(UserDefaults.standard)(true, forKey: "isUserLoggedIn");


self.dismiss(animated: true, completion: nil)


} else {
// display an alert message
let userMessage = parseJSON["message"] as? String
let myAlert = UIAlertController(title: "Alert", message: userMessage, preferredStyle: UIAlertControllerStyle.alert);
let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler:nil)
myAlert.addAction(okAction);
self.present(myAlert, animated: true, completion: nil)
}

}
} catch
{
print(error)
}


}



}

task.resume()


}

override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{

if segue.identifier == "loginView" {
let createViewController: ViewController = segue.destination as! ViewController
createViewController.communities = communitiesBox
print (communitiesBox)
}


}



}

Answer

You can done that using two ways.

Declare one Array of type [[String:String]] and use that with your TableView.

var communitiesArray = [[String:String]]()

let task = URLSession.shared.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in

    let json = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String:AnyObject]
    if let arr = json["communities"] as? [[String:String]] {
        self.communitiesArray = arr
    }      
    DispatchQueue.main.async {
        self.tableView.reloadData()
    }

Now in tableView method set use communitiesArray like cell.label.text = self.communitiesArray[indexPath.row]["name"]

If you are getting only name value with your communities then it is batter if you create just array of type [String] like this.

var communitiesArray = [String]()

let task = URLSession.shared.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in

    let json = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String:AnyObject]
    if let arr = json["communities"] as? [[String:String]] {
        self.communitiesArray = arr.flatMap { $0["name"]}
    }      
    DispatchQueue.main.async {
        self.tableView.reloadData()
    }

Now in tableView method set use communitiesArray like cell.label.text = self.communitiesArray[indexPath.row]