UIApplicationDelegate в приложении iPhone никогда не вызывал ответ

Я пытаюсь запустить приложение для iPhone из симулятора часов, используя приведенный ниже код:

Подкласс WKInterfaceController

[WKInterfaceController openParentApplication:[NSDictionary dictionaryWithObject:@"red" forKey:@"color"] reply:^(NSDictionary *replyInfo, NSError *error) {
NSLog(@"replyInfo %@",replyInfo);
NSLog(@"Error: %@",error);
}];

AppDelegate.m

- (void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo reply:(void(^)(NSDictionary *replyInfo))reply
{
NSLog(@"appdelegate handleWatchKitExtensionRequest");
NSLog(@"NSDictionary: %@",userInfo);
NSLog(@"replyInfo: %@",replyInfo);
}

Ошибка, которую я получаю:

Ошибка: Ошибка домена = com.apple.watchkit.errors Код = 2 "UIApplicationDelegate в приложении iPhone никогда не вызывал ответ() в - [Приложение UIApplicationDelegate: handleWatchKitExtensionRequest: reply:]" UserInfo = 0x7f8603227730 {NSLocalizedDescription = UIApplicationDelegate в приложении iPhone никогда не вызывал ответ() в - [Приложение UIApplicationDelegate: handleWatchKitExtensionRequest: reply:]}

Ответ 1

Вам нужно вызвать блок ответа, даже если вы вернете nil. Ниже приведена ваша ошибка:

- (void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo reply:(void(^)(NSDictionary *replyInfo))reply
{
NSLog(@"appdelegate handleWatchKitExtensionRequest");
NSLog(@"NSDictionary: %@",userInfo);
NSLog(@"replyInfo: %@",replyInfo);
reply(nil);
}

Подробнее см. документацию Apple. Вы также можете вернуть NSDictionary reply(myNSDictionary); с любой информацией, которая была бы полезной для возврата к расширению Watchkit, хотя словарь может содержать только информацию, которая может быть сериализована в файле списка свойств, так что, например, вы можете передавать строки, но можете 'просто передайте словарь, содержащий ссылки на экземпляры ваших пользовательских классов, сначала не упаковывая их в NSData.

Ответ 2

Помимо того, что вы не вызываете блок ответа, это может произойти по крайней мере по нескольким причинам:

  • Ваше приложение iPhone разбилось, когда оно обрабатывало запрос и поэтому никогда не могло вызвать блок ответа. Убедитесь, что вы случайно не вставляете nil в NSMutableDictionary, так как это приведет к сбою.
  • Вы пытаетесь поставить что-то, что не может быть сериализовано в файл plist в словаре replyInfo (подсказка шляпы до @duncan-babbage). Если вам нужно передать NSAttributedString или свой пользовательский объект, убедитесь, что он соответствует NSCoding и делает следующее:

На телефоне создайте свой ответный словарь:

NSMutableDictionary *reply = [NSMutableDictionary new];
MyCustomObject *myObject = <something you need to send>;
reply[@"myKey"] = [NSKeyedArchiver archivedDataWithRootObject: myObject];
NSAttributedString *myString = <some attributed string>;
reply[@"otherKey"] = [NSKeyedArchiver archivedDataWithRootObject: myString];

И распакуйте его обратно на стороне часов:

NSData *objectData = replyInfo[@"myKey"];
MyCustomObject *myObject = [NSKeyedUnarchiver unarchiveObjectWithData: objectData];
NSData *stringData = replyInfo[@"otherKey"];
NSAttributedString *myString = [NSKeyedUnarchiver unarchiveObjectWithData: stringData];

Ответ 3

Я хотел бы добавить, что важно запустить фоновое задание в handleWatchKitExtensionRequest, как указано в documentation. Это гарантирует, что основное приложение на iPhone не будет приостановлено до отправки ответа. (Не инициирование фоновой задачи не вызывает проблемы в симуляторе или когда приложение iPhone активно, но это вызывает проблему, когда приложение iPhone неактивно.)

Код в приложении приложения для основного приложения на iPhone:

- (void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo reply:(void ( ^)( NSDictionary * ))reply
{
   __block UIBackgroundTaskIdentifier watchKitHandler;
   watchKitHandler = [[UIApplication sharedApplication] beginBackgroundTaskWithName:@"backgroundTask"
                                                               expirationHandler:^{
                                                                 watchKitHandler = UIBackgroundTaskInvalid;
                                                               }];

   if ( [[userInfo objectForKey:@"request"] isEqualToString:@"getData"] )
   {
      // get data
      // ...
      reply( data );
   }

   dispatch_after( dispatch_time( DISPATCH_TIME_NOW, (int64_t)NSEC_PER_SEC * 1 ), dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ), ^{
       [[UIApplication sharedApplication] endBackgroundTask:watchKitHandler];
    } );
}