2015-08-04 3 views
0

Я использую API Twitter для получения списка твитов. Метод должен возвращать список твитов, но проблема в том, что он возвращается до завершения запроса, что приводит к возврату пустого списка. Как это исправить? Вот исходный код метода:Функция возвращается до завершения асинхронного запроса

// 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 Ансари Вот фактическая функция:

// 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 
+0

Посмотрите на аналогичный вопрос, заданный вчера: http://stackoverflow.com/questions/31794542/ios-swift-function-that-returns-asynchronously-retrieved-value – vadian

+0

Вот подсказка: метод GET что вы используете для извлечения твитов, делает именно это (асинхронная выборка некоторых данных), вы можете smd + щелкнуть по нему и получить представление о том, как это работает. Также обратите внимание, что асинхронные функции (почти) никогда не возвращают что-то (в конце концов, это идея асинхронности) – Alladinian

+0

Вам нужно вызвать какой-то метод из закрытия, чтобы обработать полученные твиты. – Paulw11

ответ

0

Определение функции с обработчиком завершения:

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) 
    } 
+0

Итак, когда вы вызываете его, должен ли 'returntweets' удерживать массив твитов? Когда я пытаюсь использовать его в коде, он возвращает массив размером 0. – Naldhelaan

+0

вы проверили' parseJSON (response) 'is it returnig Tweets? –

+0

Я обновил вопрос, проверьте выше.' parseJSON (response) 'получает вызов непосредственно перед оператором печати, а печатный массив заполняется, поэтому проблемы не должно быть – Naldhelaan

2

Это дизайн; это «асинхронный» метод (т. е. он отключается и выполняет некоторую работу, и вызывает ваш код «успешного успеха» позже, когда это будет сделано). Причина, по которой он разработан таким образом, так что ваш основной поток не будет заблокирован в ожидании сети, что может занять неопределенное количество времени.

Это требует, чтобы вы разработали код вокруг него соответственно - вы действительно не можете иметь метод, который делает то, что вы хотите (вы называете это, оно возвращается с готовностью). Ну, вы можете (путем очереди асинхронного вызова в фоновом потоке, а затем ждать его), но затем вы застряли в ожидании сети, которую вы не хотите делать. Вместо этого вы должны изменить свой собственный метод searchQuery, чтобы сделать аналогичным образом (быть асинхронным), и его вызывающие должны обрабатывать его по мере необходимости.

Этот шаблон является приемлемым и хорошим, когда необходимо выполнить асинхронную работу, и это не так обременительно, как кажется на первый взгляд, когда вы привыкаете к нему.

(См. Ответ @ HamzaAnsari за то, как вы могли это сделать.)

+0

Да, по сути, все, что вы хотите выполнить после завершения запроса, должно идти в блок «успех» или вызываться из него. Функция должна просто вернуться прямо после вызова «GET». – JeremyP

+0

Хорошо, спасибо Бен. Я понимаю концепцию, но код - загадка. Есть ли какие-либо ресурсы, где я могу больше узнать об этом шаблоне проектирования? – Naldhelaan

Смежные вопросы