0

I am creating an ios application using swift 3 and MySQL and PHP as database. I wanted to output the data from database to a tableview but i kept having an error: Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." I tried to check the JSON encoding in PHP, and it was ok.

Here's my swift code:

class Roster: UITableViewController {

@IBOutlet weak var rosterbar: UITabBarItem!
var class_id = String()
 var values: Array! = []

override func viewDidLoad() {

}

func SelectClassName(){
    let request = NSMutableURLRequest(url: NSURL(string: "http://localhost/classdbfiles/SelectClass.php")! as URL)
    request.httpMethod = "POST"
    let postString = "class_id=\(Home.ClassVariables.class_id)"
    request.httpBody = postString.data(using: String.Encoding.utf8)


    let task = URLSession.shared.dataTask(with: request as URLRequest){
        data, response, error in
        if error != nil {
            print("error=\(error)")
            return

        }
        print("response=\(response!)")
        let responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
        print("reponseString = \(responseString!)")


    }
    task.resume()

    }



func get() {
    guard let url = URL(string: "http://localhost/classdbfiles/SelectClass.php") else { return }

    do {
        let data = try Data(contentsOf: url)
        let deserializedValues = try JSONSerialization.jsonObject(with: data)
        guard let arrayOfDictionaryValues = deserializedValues as? [[String:String]] else { return }
        values = arrayOfDictionaryValues

    } catch {
        //You should separate the different catch blocks to handle the different types of errors that occur
        print("There was an error:\(error)")
    }
    tableView.reloadData()
}

 override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return values.count
}

        override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
       let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! SpecialCell
    let maindata = values[indexPath.row] as! [String:AnyObject]

    cell.studentname.text = maindata["lastname"] as? String

    return cell
}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    SelectClassName()
    get()
    tableView.reloadData()
}

}

and here's the PHP file:

if ($result = $mysqli->query("SELECT lastname from tbl_studentinfo where class_id='".$class_id."'")) {
    $tempArray = array();
    while($row = $result->fetch_object()) {
            $tempArray = $row;
            array_push($myArray, $tempArray);
        }
    echo json_encode($myArray);
    }
$result->close();
$mysqli->close();
1
  • Make a string from the incoming Data and print it. Error 3840 is empty string or wrong format. Commented Mar 12, 2017 at 9:48

1 Answer 1

1

Lets say you received a JSON file of the form:

 {
    "members": [
        {"name": "Sarah"},
        {"name": "David"},
        {"name": "Michael"}
    ]
}

(Note that curly brackets denote a dictionary, where as square brackets an array.)

Import the JSON file in your bundle. I called mine jsonfile.json

Then use the following method to parse the JSON file and get the members i.e. a dictionary that contains the member names:

func getMemeberDictionary()-> [[String: String]]{
        guard let jsonFileURL = Bundle.main.url(forResource: "jsonfile", withExtension: "json") else {fatalError("Failed to get JSON file URl")}
        var jsonData: Data!
        var jsonDictionary: [String: AnyObject]!

        //Getting JSON data from URL
        do {
            jsonData = try Data(contentsOf: jsonFileURL)
        } catch let error as NSError{
            print(error.debugDescription)
            fatalError("Failed to initiate JSON data from URL!")
        }

        //getting top level JSON dictionary i.e. "members"
        do {
            jsonDictionary = try JSONSerialization.jsonObject(with: jsonData, options: JSONSerialization.ReadingOptions.mutableContainers) as! [String: AnyObject]
        } catch let error as NSError{
            print(error.debugDescription)
            fatalError("Failed to initiate top level JSON dictionary")
        }

        let memebers: [[String: String]] = jsonDictionary["members"] as! [[String: String]]

        for person in memebers{
            print(person["name"]!)
        }

        return memebers
    } 

This will return an array of type [[String: String]], use it to set up your table view.

This code imports all members into a table view:

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var tableView: UITableView!
    var members: [[String: String]]!

    override func viewDidLoad() {
        super.viewDidLoad()
        members = getMemeberDictionary()
    }

    func getMemeberDictionary()-> [[String: String]]{
        guard let jsonFileURL = Bundle.main.url(forResource: "jsonfile", withExtension: "json") else {fatalError("Failed to get JSON file URl")}
        var jsonData: Data!
        var jsonDictionary: [String: AnyObject]!

        //Getting JSON data from URL
        do {
            jsonData = try Data(contentsOf: jsonFileURL)
        } catch let error as NSError{
            print(error.debugDescription)
            fatalError("Failed to initiate JSON data from URL!")
        }

        //getting top level JSON dictionary i.e. "members"
        do {
            jsonDictionary = try JSONSerialization.jsonObject(with: jsonData, options: JSONSerialization.ReadingOptions.mutableContainers) as! [String: AnyObject]
        } catch let error as NSError{
            print(error.debugDescription)
            fatalError("Failed to initiate top level JSON dictionary")
        }

        let memebers: [[String: String]] = jsonDictionary["members"] as! [[String: String]]

        for person in memebers{
            print(person["name"]!)
        }

        return memebers
    }
}


extension ViewController: UITableViewDelegate, UITableViewDataSource{

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return members.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell")
        if cell == nil {
            let cell = UITableViewCell(style: .default, reuseIdentifier: "cell")
            cell.textLabel?.text = members[indexPath.row]["name"]
            return cell
        } else {
            cell?.textLabel?.text = members[indexPath.row]["name"]
            return cell!
        }
    } 
}

Result:

enter image description here

Don't hesitate to ask me any further questions you may have.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.