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

Posted

技术标签:

【中文标题】解析 JSON 数据时无法将字符串附加到数组【英文标题】:Unable to append strings to array while parsing JSON data 【发布时间】:2016-06-19 08:46:47 【问题描述】:

我在存储从 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 的打印结果在 parseJson() 方法的结果应该返回大于 0 时返回 0。

我已经打印了显示名称、赛后和帖子详细信息变量,它们都包含数据,所以问题不在于数据的提取,而在于将数据附加到数组中。

感谢提供的任何帮助,谢谢!基于 Xcode 7 和 Swift 2.2 开发 由于信息的敏感性质,对我的 JSON 源进行了清理(我已验证信息的检索是可以的)

【问题讨论】:

您的 parseJSON 方法异步执行。 NSURLSessionTask 完成块仅在 Web 请求完成后执行,这将在方法调用完成后发生。当您在viewDidLoad 中打印数组时,这还没有发生,所以它们是空的 尝试在self.testArr.append("haha")之后调用self.reloadData @RichTolley 它不起作用并返回错误“类型控制器的值没有成员 reloadData” 【参考方案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()
   
   
    

【讨论】:

此代码不起作用。在 func parseJson 上返回错误,指示未知变量 json: [JSON]? 这部分“completion:(error: nil, results: json, postDate: postdate, postDetail: postDetails, displayName: displayname)”也不能正常工作...似乎是语法错误 为“completion(true)”返回了一个新错误。错误是“调用中缺少参数标签'isDone:' 已编辑。你需要做`completion(isDone: True)。试试? 是的,但我的函数“覆盖 func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int ” displaynhamearr 仍然返回为 0 我该如何纠正?我只需要在表格视图中显示 displayNameArr、postNameArr 和 postDetailsArr 的值,因为返回计数为 0 :(【参考方案2】:

您的所有 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")
      
   

如果您想在加载数据时显示活动指示器(我会推荐),那么使用我刚刚描述的回调会更容易。

【讨论】:

这有一个错误使用未解析的标识符 dispatch_asyc。鉴于我目前的代码格式,你能给出更完整的代码吗? 我已经稍微编辑了代码,但基本上它应该可以工作。以下是关于为什么需要 dispatch_async 的非常好的解释:hackingwithswift.com/read/9/4/…

以上是关于解析 JSON 数据时无法将字符串附加到数组的主要内容,如果未能解决你的问题,请参考以下文章

将 JSON 数组附加到字符串数组

无法解析数据 JSON alamofire SwiftyJSON

无法使用参数列表调用类型“附加”

无法快速将对象附加到对象数组

JSON数组到核心数据实体

将 pandas 数据帧转换为 json 对象 - pandas