Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/104.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios UITableView在API调用完成之前加载单元格_Ios_Json_Swift_Asynchronous_Networking - Fatal编程技术网

Ios UITableView在API调用完成之前加载单元格

Ios UITableView在API调用完成之前加载单元格,ios,json,swift,asynchronous,networking,Ios,Json,Swift,Asynchronous,Networking,我正在开发这个应用程序,它可以帮助我在tweet上运行一些NLP,并使用TableView在提要中显示结果 到今天为止,我的应用程序在设备上运行了所有NLP,并使用了一个定制模型,该模型是用苹果的CreateML自然语言构建的。当我打开应用程序时,tweet将被分析并在feed中显示结果 为了提高结果的准确性,我建立了自己的API&现在调用该API进行一些额外的分析。现在的问题是,当我打开应用程序时,有某种比赛条件。在我刷新之前,提要不会显示任何内容。在控制台中,我看到提要是在运行fetchAn

我正在开发这个应用程序,它可以帮助我在tweet上运行一些NLP,并使用
TableView
在提要中显示结果

到今天为止,我的应用程序在设备上运行了所有NLP,并使用了一个定制模型,该模型是用苹果的
CreateML
自然语言构建的。当我打开应用程序时,tweet将被分析并在feed中显示结果

为了提高结果的准确性,我建立了自己的API&现在调用该API进行一些额外的分析。现在的问题是,当我打开应用程序时,有某种比赛条件。在我刷新之前,提要不会显示任何内容。在控制台中,我看到提要是在运行
fetchAndAnalyze()
时完成的,该提要将在
triplechecksential()
中的API调用未完成时获取结果

下面是关于架构的一些解释

网络API(仅相关代码):

// This function makes a call to the Twitter API & returns a JSON of a user's tweets.
static func getUserTimeline(screenName: String, completion: @escaping (JSON) -> Void) {
   client.sendTwitterRequest(request) { (response, data, connectionError) -> Void in
     if connectionError != nil {
        print("Error: \(connectionError)")
     }
     do {
        let json = try JSON(data: data!)
        completion(json)
     } catch let jsonError as NSError {
        print("json error: \(jsonError.localizedDescription)")
     }
   }
}

// This function makes a call to my API & checks the sentiment of a Tweet. 
static func checkNegativeSentiment(tweet: Tweet, completion: @escaping (JSON) -> Void) {
   let headers: HTTPHeaders = ["Content-Type": "application/json"]
   AF.request(apiURL, method: .post, parameters: tweet, encoder: JSONParameterEncoder.default, headers: headers).response {
     response in
     do {
        let json = try JSON(data: response.data!)
        completion(json)
     } catch let jsonError as NSError {
        print("json error: \(jsonError.localizedDescription)")
        completion(JSON.init(parseJSON: "API OFFLINE."))
     }
   }
}
// This function is called from the app's feed to retrieve the most recent tweets. 
func fetchTweets(completion: @escaping (Bool) -> Void) {
   for friend in Common.listOfFriends {
     NetworkingAPI.getUserTimeline(screenName: friend.handle, completion: {
        success in
        self.parseTweets() // This puts all the tweets returned in success in a list.
        self.analyze()    // Runs some NLP on the tweets. 
        completion(true)
     })
   }
}

func analyze() {
   for tweet in listOfTweets {
     // Does some on-device NLP using a model created with CreateML ...
     if sentimentScore == "0" {  // That is the tweet is negative. 
        doubleCheckSentiment(tweet: tweet)
     }
   }
}

func doubleCheckSentiment(tweet: Tweet) {
   // Does some on-device NLP using Apple's generic framework NaturalLanguage. 
   if sentimentScore <= -0.8 {   // Once again, the tweet is negative.
     tripleCheckSentiment(tweet: tweet)
   }
}

func tripleCheckSentiment(tweet: Tweet) {
   NetworkingAPI.checkNegativeAzureSentiment(tweet: tweet, completion: {
     json in
     if json["value"]["sentiment"].int! == 2 {  // We confirm the tweet is negative.
        Common.negativeTweets.append(tweet)
     }
   }
}
// This function gets called when the view appears & at a bunch of different occasions.
func fetchAndAnalyze() {
   var friendsAnalyzed = 0
   tweetManager.fetchTweets(completion: {
     success in
     friendsAnalyzed += 1  // Every time completion hits, it means one friend was analyzed. 
     if friendsAnalyzed == Common.listOfFriends.count {  // Done analyzing all friends.
        self.tableView.reloadData()    // Refresh & show the tweets in Common.negativeTweets in table. 
   }
}
TweetManager(仅相关代码):

// This function makes a call to the Twitter API & returns a JSON of a user's tweets.
static func getUserTimeline(screenName: String, completion: @escaping (JSON) -> Void) {
   client.sendTwitterRequest(request) { (response, data, connectionError) -> Void in
     if connectionError != nil {
        print("Error: \(connectionError)")
     }
     do {
        let json = try JSON(data: data!)
        completion(json)
     } catch let jsonError as NSError {
        print("json error: \(jsonError.localizedDescription)")
     }
   }
}

// This function makes a call to my API & checks the sentiment of a Tweet. 
static func checkNegativeSentiment(tweet: Tweet, completion: @escaping (JSON) -> Void) {
   let headers: HTTPHeaders = ["Content-Type": "application/json"]
   AF.request(apiURL, method: .post, parameters: tweet, encoder: JSONParameterEncoder.default, headers: headers).response {
     response in
     do {
        let json = try JSON(data: response.data!)
        completion(json)
     } catch let jsonError as NSError {
        print("json error: \(jsonError.localizedDescription)")
        completion(JSON.init(parseJSON: "API OFFLINE."))
     }
   }
}
// This function is called from the app's feed to retrieve the most recent tweets. 
func fetchTweets(completion: @escaping (Bool) -> Void) {
   for friend in Common.listOfFriends {
     NetworkingAPI.getUserTimeline(screenName: friend.handle, completion: {
        success in
        self.parseTweets() // This puts all the tweets returned in success in a list.
        self.analyze()    // Runs some NLP on the tweets. 
        completion(true)
     })
   }
}

func analyze() {
   for tweet in listOfTweets {
     // Does some on-device NLP using a model created with CreateML ...
     if sentimentScore == "0" {  // That is the tweet is negative. 
        doubleCheckSentiment(tweet: tweet)
     }
   }
}

func doubleCheckSentiment(tweet: Tweet) {
   // Does some on-device NLP using Apple's generic framework NaturalLanguage. 
   if sentimentScore <= -0.8 {   // Once again, the tweet is negative.
     tripleCheckSentiment(tweet: tweet)
   }
}

func tripleCheckSentiment(tweet: Tweet) {
   NetworkingAPI.checkNegativeAzureSentiment(tweet: tweet, completion: {
     json in
     if json["value"]["sentiment"].int! == 2 {  // We confirm the tweet is negative.
        Common.negativeTweets.append(tweet)
     }
   }
}
// This function gets called when the view appears & at a bunch of different occasions.
func fetchAndAnalyze() {
   var friendsAnalyzed = 0
   tweetManager.fetchTweets(completion: {
     success in
     friendsAnalyzed += 1  // Every time completion hits, it means one friend was analyzed. 
     if friendsAnalyzed == Common.listOfFriends.count {  // Done analyzing all friends.
        self.tableView.reloadData()    // Refresh & show the tweets in Common.negativeTweets in table. 
   }
}
我知道这很长&我深表歉意,但如果我能在这方面得到一些帮助,我将非常感激!顺便说一句,请原谅我使用@escaping&所有这些,我对处理异步API调用相当陌生

谢谢

**EDIT,在实现了jawadAli的解决方案后,由于某种原因,该解决方案在某些情况下有效,我注意到以下模式:**

想象一下,我在朋友列表中添加了一个朋友。然后我刷新,它调用
fetchAndAnalyze()
。我们在调用的日志
中看到。
&函数调用结束时,没有发现负面推文。就在这件事发生之后,我们从API调用中得到一个结果,其中一条推文被发现为负面消息


如果我再次刷新,则会显示该tweet。有什么线索吗?

此函数有问题。在第一次横切for loop时,您的完成将被解雇

func fetchTweets(completion: @escaping (Bool) -> Void) {
    let myGroup = DispatchGroup()
   for friend in Common.listOfFriends {
        myGroup.enter()
     NetworkingAPI.getUserTimeline(screenName: friend.handle, completion: {
        success in

       self.parseTweets() 
       self.analyze()  
       myGroup.leave()

     })
   }
}
 myGroup.notify(queue: DispatchQueue.main) {
      
        completion(true)
})
还要在主线程上重新加载数据

  DispatchQueue.main.async {
        self.tableView.reloadData()
    }

注意:您需要相应地处理成功和失败案例。。我只是想知道如何使用dispatchGroup来同步呼叫…

据我所知,您在
fetchTweets
函数中多次调用
NetworkingAPI.getUserTimeline
,但您没有等待所有响应完成。@omerfarukozturk,是的!这就是我所理解的&似乎是什么导致了这个问题。我尝试了很多不同的方法,你能告诉我如何解决这个问题吗?你可以用以下方法解决它,@omerfarukozturk
let myGroup=DispatchGroup()for friend in Common.listOfFriends{myGroup.enter()NetworkingAPI.getUserTimeline(屏幕名:friend.handle,完成:{Success in self.parseTweets()self.Analysis()count+=1如果count==Common.listOfFriends.count{myGroup.leave()}}}}myGroup.notify(queue:DispatchQueue.main,execute:{completion(true)})
它没有工作,很遗憾。当打印
count
时,我会在API调用打印其JSON之前达到最大值。顺便说一句,您需要调用
leave()
在每次完成时,不仅仅是当
count==Common.listofriends.count
时。非常感谢,这帮了我很大的忙。我仍然需要了解DispatchGroup是如何工作的,但这对我来说是个窍门!嗯,这很奇怪。似乎如果我的列表中有多个朋友,它工作得很好。但是,如果我只有一个朋友,它仍然会给我带来更多的快乐同样的问题。它不应该…调试它来检查发生了什么。你能看看编辑并告诉我你是否有任何线索正在发生什么吗?这是我能够调试的。