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);
}

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

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


person Abhishek Bedi    schedule 08.01.2015    source источник
comment
Я совсем не знаком с WatchKit, но ошибка, похоже, указывает на то, что ваш код в handleWatchKitExtensionRequest: должен вызывать блок response(), предоставленный в качестве аргумента этому методу. Попробуйте добавить reply(@{@"data" : @"test data"}); к этому методу. Это использование просто тривиального словаря в качестве теста; Я думаю, документы WatchKit точно скажут вам, каким должно быть содержимое этого словаря.   -  person pbasdf    schedule 08.01.2015
comment
Да, я получаю ту же ошибку, когда печатаю ошибку в [InterfaceController openParentApplication:dict response:^(NSDictionary *replyInfo, NSError *error) {NSLog(@%@,[replyInfo objectForKey:@Key]); NSLog(@error:-%@,[описание ошибки]); подскажите, пожалуйста, как получить данные в приложении watchkit с помощью этого метода. я хочу, чтобы строка из моего приложения смотрела приложение комплекта. заранее спасибо   -  person jaydev    schedule 14.03.2015


Ответы (3)


Вам нужно вызвать блок ответа, даже если вы вернете 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.

person Duncan Babbage    schedule 08.01.2015
comment
Вау, мне потребовалась целая вечность, чтобы понять, что вы не можете передавать пользовательские объекты в словарь replyInfo. Даже соответствие NSCoding не помогает. И сообщение об ошибке, в котором говорится, что вы никогда не вызывали блок ответа, вводит в заблуждение, когда реальная проблема заключается в словаре replyInfo. - person bdmontz; 11.03.2015
comment
@bdmontz В отличие от сервисов XPC, похоже, что регистрация пользовательских классов не предусмотрена. Облом! Возможно, вам следует опубликовать это как еще один ответ. - person GoodSp33d; 16.03.2015
comment
Я не понимаю, почему в блоке ответа openParentApplication ожидается параметр ошибки, а в блоке handleWatchKitExtensionRequest нет параметра ошибки для возврата? - person Van Du Tran; 04.05.2015
comment
Вы также можете получить эту ошибку, если приложение iPhone дает сбой при обработке запроса. - person olegam; 13.05.2015
comment
если iPhone неактивен, я также получаю эту ошибку Error: Error Domain=com.apple.watchkit.errors Code=2 "The UIApplicationDelegate in the iPhone App never called reply() in -[UIApplicationDelegate application:handleWatchKitExtensionRequest:reply:]" UserInfo=0x7f8603227730 {NSLocalizedDescription=The UIApplicationDelegate in the iPhone App never called reply() in -[UIApplicationDelegate application:handleWatchKitExtensionRequest:reply:]} - person Min Soe; 21.05.2015

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

  1. Ваше приложение для iPhone аварийно завершило работу во время обработки запроса и, следовательно, не смогло вызвать блок ответа. Убедитесь, что вы случайно не поместили nil в NSMutableDictionary, так как это приведет к сбою.
  2. Вы пытаетесь поместить что-то, что не может быть сериализовано в файле 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];
person bdmontz    schedule 17.03.2015
comment
Вы забыли упомянуть, что для использования архивации вам необходимо соответствовать протоколу <NSCopying>, который требует реализации необходимых методов. - person E-Riddie; 21.04.2015
comment
@EridB, это неправильно. Как указано в моем ответе, ваш объект должен соответствовать протоколу NSCoding для использования архивации. - person bdmontz; 22.04.2015
comment
@bdmontz спасибо, что спасли мой бекон! Я бы потратил день, пытаясь понять это! Я также создал классную категорию NSDictionary, чтобы скрыть от меня всю эту ерунду. - person eric; 25.04.2015

Я хотел бы добавить, что важно запустить фоновую задачу в handleWatchKitExtensionRequest, как указано в документация. Это гарантирует, что основное приложение на 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];
    } );
}
person vomako    schedule 03.05.2015