解析JSON数据时无法将字符串附加到数组

时间:2016-06-19 08:46:47

标签: ios json swift uitableview

我在存储从JSON源数据中检索到的结果时遇到困难。我已经确认能够打印检索到的数据,但无法存储到我的本地数组中。

我的最终目标是在UITableView中实际打印结果。

以下是我的相关表格视图控制器的代码:

import UIKit

class CommunityActivityTableViewController: UITableViewController {
    var displayNameArr = [String]()
    var postDateArr = [String]()
    var postDetailArr = [String]()
    var testArr = ["teaad"]

    override func viewDidLoad() {
        super.viewDidLoad()
        parseJson()
        print(self.displayNameArr.count) //returns 0
        print(self.postDateArr.count) //returns 0
        print(self.postDetailArr.count) //returns 0
        print(self.testArr.count)
        print("end")

    }
    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        // #warning Incomplete implementation, return the number of sections

        return 1
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

        // #warning Incomplete implementation, return the number of rows

        return self.displayNameArr.count
    }



    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        print("3")
        let cell = tableView.dequeueReusableCellWithIdentifier("Cell_activity", forIndexPath: indexPath)



        print("hi")
        cell.textLabel?.text = "hi"
        cell.detailTextLabel?.text = "test"

        return cell
    }
    override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        return UITableViewAutomaticDimension
    }
    override func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        return UITableViewAutomaticDimension
    }
    func makeAttributedString(title title: String, subtitle: String) -> NSAttributedString {
        let titleAttributes = [NSFontAttributeName: UIFont.preferredFontForTextStyle(UIFontTextStyleHeadline), NSForegroundColorAttributeName: UIColor.purpleColor()]
        let subtitleAttributes = [NSFontAttributeName: UIFont.preferredFontForTextStyle(UIFontTextStyleSubheadline)]

        let titleString = NSMutableAttributedString(string: "\(title)\n", attributes: titleAttributes)
        let subtitleString = NSAttributedString(string: subtitle, attributes: subtitleAttributes)

        titleString.appendAttributedString(subtitleString)

        return titleString
    }
    func parseJson(){
        //MARK: JSON parsing
        let requestURL: NSURL = NSURL(string: "<sanitised>")!
        let urlRequest: NSMutableURLRequest = NSMutableURLRequest(URL: requestURL)
        let session = NSURLSession.sharedSession()
        let task = session.dataTaskWithRequest(urlRequest) {
            (data, response, error) -> Void in

            let httpResponse = response as! NSHTTPURLResponse
            let statusCode = httpResponse.statusCode

            if (statusCode == 200) {
                print("Everyone is fine, file downloaded successfully.")

                do{

                    let json = try NSJSONSerialization.JSONObjectWithData(data!, options:.AllowFragments)

                    if let results = json["result"] as? [[String: AnyObject]] {

                        for result in results {

                            if let lastname = result["last_name"] as? String {

                                if let postdate = result["timestamp"] as? String {
                                    if let firstname = result["first_name"] as? String {
                                        if let postdetails = result["post_details"] as? String {

                                            let displayname = firstname + " " + lastname
                                            //print(displayname)
                                            self.displayNameArr.append(displayname)
                                            self.postDateArr.append(postdate)
                                            self.postDetailArr.append(postdetails)
                                            self.testArr.append("haha")


                                        }
                                    }

                                }

                            }
                        }

                    }

                }catch {
                    print("Error with Json: \(error)")
                }

            }
        }

        task.resume()}


}

根据上面的代码,displaynamearr.count和postDateArr.count以及postDetailArr.count的打印结果返回0,因为parseJson()方法应该返回0以上。

我已经打印了显示名称,postgame和post details变量,它们都包含数据,因此问题不在于数据的提取,而在于将数据附加到数组中。

感谢您提供的任何帮助!在Xcode 7和Swift 2.2上开发 由于信息的敏感性而对我的JSON源进行了清理(我已经验证了信息的检索是否正常)

2 个答案:

答案 0 :(得分:1)

dataTaskWithRequest()是异步数据加载。它加载在后台线程上,确保您的UI不会冻结。因此,当您执行此操作时,您的数组将为空,从而导致您的错误。你需要像这样的完成处理程序:

   func parseJson(completion: (isDone: Bool) -> ()){

///code

for result in results {

                            if let lastname = result["last_name"] as? String {

                                if let postdate = result["timestamp"] as? String {
                                    if let firstname = result["first_name"] as? String {
                                        if let postdetails = result["post_details"] as? String {

                                            let displayname = firstname + " " + lastname
                                            //print(displayname)
                                            self.displayNameArr.append(displayname)
                                            self.postDateArr.append(postdate)
                                            self.postDetailArr.append(postdetails)
  self.testArr.append("haha")


       }
completion(isDone: True)

   }



}

现在在viewDidLoad:

 override func viewDidLoad() {
            super.viewDidLoad()
            parseJson(){ success in
            if success{
            print(self.displayNameArr.count) //returns a value
            print(self.postDateArr.count) //returns a value
            print(self.postDetailArr.count) //returns a value
            print(self.testArr.count) //This wont because I havent added it in the completion handler
            print("end")
       self.tableView.reloadData()
   }
   }
    }

答案 1 :(得分:0)

所有UI更新都在主线程上运行。如果您执行类似

的操作
let task = session.dataTaskWithRequest(urlRequest) {
            (data, response, error) -> Void in
   // ...
}.resume()

您在另一个线程(而不是主线程)上异步启动任务。您的iPhone正在执行网络请求,这需要一些时间。所以我想当你的cellForRowAtIndexPath委托方法被调用时,你还没有收到任何数据。这就是你没有看到任何东西的原因。

最简单的解决方案是在收到数据后重新加载表格视图。当您完成parseJson方法中的所有解析(在所有循环之外)时,只需运行:

dispatch_async(dispatch_get_main_queue()) {
   self.tableView.reloadData()  
}

这会强制您的表格视图更新。请记住,您必须运行更新主线程上的UI的代码。这就是dispatch_async(dispatch_get_main_queue()) {}的作用。

编辑:上面的答案是向你说明问题。更优雅的解决方案是使用像这样的完成处理程序:

func parseJson(completionHandler: (Bool) -> Void) {
   //do all your json parsing.
   //....
   dispatch_asyc(dispatch_get_main_queue()) {
      //run this if you received the data
      //implement some kind of if statement that checks if the parsing was successful
      completionHandler(true)

      //run this if it failed
      completionHandler(false)
   }
 }

在你的viewDidLoad中,你会做类似

的事情
override func viewDidLoad() {
   super.viewDidLoad()
   //...
   parseJson() { success in
      tableView.reloadData()
      if(success) {
         print("success")
      }
   }
}

如果你想在加载数据时显示一个活动指示器(我建议这样做),就像我刚刚描述的那样,使用回调更容易。