2015-07-07 6 views
1

Мой вопрос очень похож на несколько других here, но я просто не могу заставить его работать. Я делаю вызов API через класс-помощник, который я написал.Захват значений закрытия в Swift

Сначала я попробовал стандартную функцию с возвращаемым значением, и результат был таким, как ожидалось. Фоновая задача выполнена после того, как я устал назначать результат.

Теперь я использую закрытие, и я могу вернуть значение в контроллер своего вида, но его все еще застрял в закрытии, у меня такая же проблема. Я знаю, что мне нужно использовать GCD, чтобы получить назначение в главной очереди.

это то, что у меня в контроллере

var artists = [String]() 
let api = APIController() 
    api.getArtistList("foo fighters") { (thelist) -> Void in 
     if let names = thelist { 
      dispatch_async(dispatch_get_main_queue()) { 
       artists = names 
       print("in the closure: \(artists)") 
      } 
     } 
    } 

    print ("method 1 results: \(artists)") 

зрения как результаты:

method 1 results: [] 
in the closure: [Foo Fighters & Brian May, UK Foo Fighters, John Fogerty with Foo Fighters, Foo Fighters, Foo Fighters feat. Norah Jones, Foo Fighters feat. Brian May, Foo Fighters vs. Beastie Boys] 

Я знаю, почему это происходит, я просто не знаю, как это исправить: (API-вызовы должны быть асинхронными, поэтому какова наилучшая практика для сбора этих результатов? Основываясь на том, что пользователь выбирает в виде таблицы, я буду делать последующие вызовы api, так что это не так, как я могу обрабатывать все внутри закрытия

ответ

1

Простое решение - сделать все, что вы делаете, на своем print(), внутри укупорочного средства.

С тех пор, как вы уже находитесь dispatch_async В главной очереди (основной/графический поток) вы можете выполнить любую обработку там. Нажмите новый контроллер вида, представите некоторые модальные данные, обновите текущий контроллер и т. Д.

Просто убедитесь, что у вас нет нескольких потоков, изменяющих/получающих доступ к вашим локальным/кэшированным данным, которые отображаются. Особенно, если он используется /UITableViewDataSource реализациями, которые будут бросать припадки, если вы начнете получать ничего немыслимые или несовместимые с вашими возвращаемыми значениями.

Пока вы можете получать данные в фоновом режиме, и только обработку, которая должна происходить в основном потоке является переменным переназначением экземпляра, или каким-то массив, добавляя, просто сделать на главном потоке , используя данные, которые вы извлекли на задней панели. Это не тяжело. Если это тяжело, то вам понадобятся более сложные методы синхронизации для защиты ваших данных.

Обычно картина выглядит следующим образом:

dispatch_async(getBackgroundQueue(), { 
    var theData = getTheDataFromNetwork(); 
    dispatch_async(dispatch_get_main_queue() { 
     self.data = theData // Update the instance variable of your ViewController 
     self.tableView.reloadData() // Or some other 'reload' method 
    }); 
}) 

Так где вы обычно обновить представление таблицы или известите ViewController, что операция завершена (или, что локальные данные были обновлены), вы должны продолжать ваши обработка основной нити.

+0

Это прекрасно работает. Представление сначала загружается пустой таблицей, а затем заполняется. – rjb101

+0

Без проблем Роберт. Я настоятельно рекомендую вложить несколько минут в https://github.com/jdg/MBProgressHUD. Я не автор, но это моя плавная рамка для опускания в накладке быстрой загрузки, ожидая появления данных. Если у пользователя нет сетевого подключения, они могут задаться вопросом - он все еще думает? –

4

Я полностью согласен с предложением @Craig использования НОД, но ваш вопрос связан запрос вызова API каждый раз, когда вы выбираете строку, вы можете сделать следующее:

  • Давайте предположим, что вы используете метод tableView:didSelectRowAtIndexPath: для обработки выбора, то вы можете сделать следующее внутри него:

    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { 
        // it is just a form to get the item 
        let selectedItem = items.objectAtIndex(indexPath.row) as String 
    
        api.getArtistList(selectedItem) { (thelist) -> Void in 
         if let names = thelist { 
          dispatch_async(dispatch_get_main_queue()) { 
           artists = names 
          } 
         } 
        } 
    } 
    

и тогда вы можете наблюдать свойство и обрабатывать вы в nt внутри него:

var artists: [String] = [] { 
    didSet { 
     self.tableView.reloadData() // or anything you need to handle. 
    } 
} 

Это просто еще один способ его увидеть. Надеюсь, это поможет вам.

+0

Спасибо за дополнительную информацию, это именно то, что мне нужно было сделать дальше – rjb101

+0

Хорошее решение - 'didSet' - действительно эффективный способ справиться с такими вещами. –

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