2016-09-18 1 views
0

Итак, после многих игр, я выяснил, как это сделать, но у меня есть одна вещь, которую я не понял как обойти (и сводит меня с ума ..).Получение общих данных API GooglePlaces (и асинхронных вызовов в целом) для AppleWatch (с использованием WCSession)

У меня есть приложение для часов, которым нужны данные из GooglePlaces (без интерфейса для iOS еще ...). Итак - я использую WCSession и использую телефон, используя sendMessage, для запроса GooglePlaces по телефону, возвращая соседние места на часы.

Для начала, по-видимому GooglePlaces currentPlace функция вызывается в том же потоке она привлекаемое к (по очереди его позже) - проблема, так как это запланировано, когда после того, как программа будет закрыта (с функцией didReceiveMessage выходы до его вызова). Поэтому вместо того, чтобы запускать его в основной очереди, я запускаю поток и запускаю этот код на нем.

Ошибка в том, что replyHandler должен быть вызван до того, как session:didReceiveMessage завершит выполнение (в противном случае процесс будет убит, если приложение находится в фоновом режиме).

Так код, который я построил, чтобы обойти этот вопрос выглядит следующим образом (Примечание У меня есть вложенный код cloudKit там ..):

let queue = OperationQueue(); 

var finishedRunning = false; 
queue.addOperation{ 
    sleep(1); 
    self.placesClient?.currentPlace(callback: { 
     (placeLikelihoodList: GMSPlaceLikelihoodList?, error: Error?) ->() in 
     if let err = error { 
      retVal.removeAll(); 
      retVal["error"] = err.localizedDescription; 
      finishedRunning = true; 
      return; 
     } 

     let predicate = NSPredicate(format: "selected = 1"); 
     let query = CKQuery(recordType: "someInfo", predicate: predicate); 

     let privDb = CKContainer.default().privateCloudDatabase; 
     privDb.perform(query, inZoneWith: nil, completionHandler: {records, error in 

      if let err = error { 
       retVal.removeAll(); 
       retVal["error"] = err.localizedDescription; 
       finishedRunning = true; 
       return; 
      } 
      retVal["completed"] = 1; 
      finishedRunning = true; 
     }); 
    }); 
} 

while !finishedRunning{ 
    sleep(1); 
} 
marker = true; 
replyHandler(retVal); 

Те, кто читает код тщательно заметил, что я добавил команду sleep(1); вверх там ... сразу после начала очереди.

Непонятно, почему, но без этого вызова сна, обратный вызов GooglePlaces не вызывается!

Я бы очень хотел удалить этот звонок. Есть ли у кого-нибудь идеи, почему это происходит? Как обходить его?

(P.S. Я не уверен, что замки необходимы для защиты finishedRunning .. так как это работает, я полагаю, что нет необходимости).

P.S. # 2 - Я знаю, что это «грязно», но нет другого способа обойти это ... так как я хочу эти данные на часах, я отказался от элегантности ...

Спасибо!

+0

Это не соответствует моему опыту: _ «Проблема в том, что replyHandler должен быть вызван до сеанса: doneReceiveMessage заканчивается (иначе процесс будет убит, если приложение находится в фоновом режиме). _; на чем вы основываете это? – ccjensen

+0

Отладка и другие сообщения здесь ... – evenro

+0

Возможно, я ошибался, но это ведет себя странно, когда вызывается какой-либо асинхронный метод. – evenro

ответ

0

Проблема оказалась иначе, чем я ожидал ...

Похоже NSUserDefaults не «ожидания» для себя должен быть загружен, прежде чем дать доступ к его содержанию:
В моем коде, я прочитал перед ним конфигурация. Кода был:

let config :UserDefaults = UserDefaults(); 
// read config 

бы, чтобы изменить:

let config :UserDefaults = UserDefaults(); 
config.synchronize(); 
// read config 

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

в результате код умирает, и убивая всю сессию ..

Однократная задержка позволила асинхронному процессу завершить загрузку и вернуть ожидаемое значение ...

0

По моему опыту sendMessagereplayHandler не нужно вызывать перед возвратом метода делегата, но если вы хотите сохранить это поведение, вы можете избавиться хотя бы от одного из «сна» (1), так что :

<...> 
queue.waitUntilAllOperationsAreFinished() 
marker = true; 
replyHandler(retVal); 

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

+0

Это был мой начальный код, но процесс приложения начался и сразу же вышел из него, предположив, что функция была вызвана, и после того, как она вернулась, процесс был закрыт .. в любом случае, я попробую функцию wait позже и продолжу публикацию. Благодаря! – evenro

+0

Итак, теперь я уверен (после обращения к поддержке Apple), что основной поток должен оставаться живым с вызовом replyHandler, но я не уверен, что если replyHandler должен быть вызван из основного потока .. (похоже на него возможно) ... Я буду продолжать обновлять здесь .. все еще борюсь с этой проблемой ... – evenro