【问题标题】:Function returns before asynchronous request finishes函数在异步请求完成之前返回
【发布时间】:2015-08-04 09:29:10
【问题描述】:

我正在使用 Twitter API 来检索推文列表。该方法应该返回推文列表,但问题是它在请求结束之前返回,这导致返回一个空列表。我该如何解决?以下是该方法的源代码:

// Call to search through twitter with a query
func searchQuery(query: String) -> [Tweet] {
    var tweets: [Tweet] = []
    var query_URL = query.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())
    if let query_URL = query_URL {
        TwitterClient.sharedInstance.GET("https://api.twitter.com/1.1/search/tweets.json?q=\(query_URL)", parameters: nil, success: { (operation: AFHTTPRequestOperation!, response: AnyObject!) -> Void in
            tweets = parseJSON(response)
            println(tweets.count)
            }, failure: { (operation: AFHTTPRequestOperation!, error: NSError!) -> Void in

        })
    }
    println("ret: \(tweets.count)")
    return tweets
}

在上面的代码中,输出将是

ret: 0
15

我尝试过使用调度组,但无法让它们工作。以下是我对 GCD 所做的:

// Call to search through twitter with a query
func searchQuery(query: String) -> [Tweet] {
    var tweets: [Tweet] = []
    var query_URL = query.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())
    var group = dispatch_group_create()
    if let query_URL = query_URL {
        dispatch_group_enter(group)
        TwitterClient.sharedInstance.GET("https://api.twitter.com/1.1/search/tweets.json?q=\(query_URL)", parameters: nil, success: { (operation: AFHTTPRequestOperation!, response: AnyObject!) -> Void in
            tweets = parseJSON(response)
            dispatch_group_leave(group)
            }, failure: { (operation: AFHTTPRequestOperation!, error: NSError!) -> Void in
                dispatch_group_leave(group)
        })
    }

    dispatch_group_wait(group, DISPATCH_TIME_FOREVER)
    return tweets
}

但是,该代码似乎永远等待。

作为参考,Tweet 是一个用于保存与推文相关的数据的结构。我用它以更紧凑的方式移动大量数据。 parseJSON 根据 JSON 响应填充并返回一组推文。理想情况下,返回的数组将保存到 tweets,然后它应该从方法返回,但这不会发生。

任何克服这个问题的想法或技术将不胜感激!

编辑:@Hamza Ansari 这是实际的功能:

// Call to search through twitter with a query
func searchQuery(query: String, completionHandler:(returntweets: [Tweet]) -> Void) {
    var query_URL = query.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())
    if let query_URL = query_URL {
        TwitterClient.sharedInstance.GET("https://api.twitter.com/1.1/search/tweets.json?q=\(query_URL)", parameters: nil, success: { (operation: AFHTTPRequestOperation!, response: AnyObject!) -> Void in
            var tweets:[Tweet] =  parseJSON(response)
            println("size in method: \(tweets.count)")
            completionHandler(returntweets: tweets)

            }, failure: { (operation: AFHTTPRequestOperation!, error: NSError!) -> Void in

        })
    }
}

但是,当在用于初始化数据源的不同方法中调用时:

// Initializes the data source
func initialize(query: String) {
    self.query = query
    searchQuery(query, { (returnTweets) -> Void in
        self.searches = returnTweets
        })

    println("size when called: \(searches.count)")
}

输出(按顺序):

size when called: 0
size in method: 15

【问题讨论】:

  • 看看昨天问的类似问题:stackoverflow.com/questions/31794542/…
  • 这里有一个提示:您用于获取推文的 GET 方法就是这样做的(异步获取一些数据),您可以 cmd+单击它并了解如何操作有用。另请注意,异步函数(几乎)永远不会返回某些内容(毕竟这是异步背后的想法)
  • 您需要从闭包中调用一些方法来处理已检索到的推文。
  • 这是因为您在块外使用println("size when called: \(searches.count)")
  • searchQuery(query, { (returnTweets) -> Void in self.searches = returnTweets println("size when called: \(searches.count)" })

标签: ios swift asynchronous grand-central-dispatch


【解决方案1】:

这是设计使然;这是一个“异步”方法(即,它关闭并执行一些工作,并在完成后调用您提供的“成功”代码)。这样做的原因是您的主线程不会被阻塞等待网络,这可能需要不确定的时间。

这需要您相应地围绕它设计代码——您不能真正拥有一个方法来做您想做的事情(您调用它,它会返回并准备好结果)。好吧,您可以(通过在后台线程上对异步调用进行排队,然后等待它),但是您却被困在等待您不想做的网络。相反,您应该更改自己的方法 searchQuery 以进行类似的操作(异步),并且其调用者应根据需要进行处理。

当需要完成异步工作时,这种模式既可以接受也很好,一旦你习惯了它,它就不像最初看起来那样繁重。

(请参阅@HamzaAnsari 的回答,了解如何做到这一点。)

【讨论】:

  • 是的,基本上,您希望在请求完成后发生的所有事情都需要进入“成功”块或从中调用。该函数应该在GET 调用之后直接返回。
  • 好的,谢谢本。我理解这个概念,但代码是一个谜。是否有任何资源可以让我了解有关此设计模式的更多信息?
【解决方案2】:

使用完成处理程序定义函数:

func searchQuery(query: String, completionHandler:(returntweets: [Tweet]) -> Void) {
    var query_URL = query.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())
    if let query_URL = query_URL {
      TwitterClient.sharedInstance.GET("https://api.twitter.com/1.1/search/tweets.json?q=\(query_URL)", parameters: nil, success: { (operation: AFHTTPRequestOperation!, response: AnyObject!) -> Void in
        var tweets:[Tweet] =  parseJSON(response)
        println(tweets.count)
        completionHandler(returntweets: tweets)

        }, failure: { (operation: AFHTTPRequestOperation!, error: NSError!) -> Void in

      })
    }
  }

现在在你需要推文的地方调用它:

searchQuery(query: "youQuery",{ (returntweets) -> Void in
      //Do something 
     println(returntweets.count)
    }

【讨论】:

  • 那么,当你调用它时,returntweets 是否应该保存推文数组?当我在代码中尝试它时,它返回一个大小为 0 的数组。
  • 你检查过parseJSON(response) 是否返回推文?
  • 我已经更新了问题,请查看上方。 parseJSON(response) 在 print 语句之前被调用,并且打印的数组被填充,所以问题不应该存在。
猜你喜欢
  • 2020-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多