IOS `scene:continueUserActivity:` взаимоблокировка при вызове синхронизированного APIIOS

Программируем под IOS
Ответить Пред. темаСлед. тема
Anonymous
 IOS `scene:continueUserActivity:` взаимоблокировка при вызове синхронизированного API

Сообщение Anonymous »

Что мне нужно
Я хочу преобразовать асинхронный системный API в синхронизированный и вызвать его внутри continueUserActivity SceneDelegate.
Примечание: я полностью понимаю, что преобразование асинхронных операций в синхронные не одобряется. Но есть разница между «как это сделать?» и «правильно ли это сделать?». Этот вопрос больше касается "как это сделать".
Что работает
У меня есть следующий код:< /p>
// Imagine this is a system async API that:
// (1) has to be called on main thread; and
// (2) it also completes on main thread.
- (void)systemAsyncAPI:(void(^)(void))completion {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
completion();
});
}

// Convert the system API from async to sync
- (void)synchronizedSystemAPI {
__block BOOL completed = NO;

[self systemAsyncAPI:^{
completed = YES;
}];

while (!completed) {
NSLog(@"Tick");
[NSRunLoop.currentRunLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
}
NSLog(@"completed");
}


Теперь, когда я использую этот код внутри willConnectToSession SceneDelegate:
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
[self synchronizedSystemAPI];
}

Все работает как положено, со следующим журналом:
Tick
Tick
Tick
completed

Что не работает
Теперь вместо того, чтобы вызывать это в willConnectToSession, мне нужно вызвать это в continueUserActivity:
- (void)scene:(UIScene *)scene continueUserActivity:(NSUserActivity *)userActivity {
[self synchronizedSystemAPI];
NSLog(@"Continue my other work after system API is complete");
}

Этот код теперь находится в тупике, поскольку он тикает вечно:
Tick
Tick
Tick
Tick
Tick
Tick
Tick
Tick
Tick
...

Насколько я понимаю
Вдохновленный этим ответом, я думаю, причина в том, что willConnectToSession вызывается по старой технологии (до GCD), которая не является отправкой. continueUserActivity является частью элемента отправки в основной очереди, отсюда и взаимоблокировка, как описано в связанном ответе.
Как протестировать код?
Простой способ вызвать continueUserActivity — использовать поиск Spotlight:
  • добавьте массив NSUserActivityTypes в Info.plist< /код>. Здесь я поместил один элемент "foo".
[img]https://i.sstatic. net/rIz9sskZ.png[/img]
  • настройте активность:
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
NSUserActivity *activity = [[NSUserActivity alloc] initWithActivityType:@"foo"];
activity.title = @"foo title";
activity.eligibleForSearch = YES;
[activity becomeCurrent];
}
  • Запустите приложение.
  • Перейдите на главный экран и выполните поиск по запросу "foo title" в центре внимания. поиск.
  • У вас должно быть это приложение. Нажмите на него, чтобы возобновить работу.
  • Обратите внимание, что будет вызван continueUserActivity.
И вот мой полный воспроизводимый код. Не забудьте добавить NSUserActivityTypes в Info.plist, как описано выше.

@implementation SceneDelegate

// A system async API that has to be called on main thread, and it also completes on main thread.
- (void)systemAsyncAPI:(void(^)(void))completion {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
completion();
});
}

// Convert the above system API from async to sync
- (void)synchronizedSystemAPI {
__block BOOL completed = NO;

// Imagine this is a system API that must be called on main thread, and completes on main thread.
[self systemAsyncAPI:^{
completed = YES;
}];

while (!completed) {
NSLog(@"Tick");
[NSRunLoop.currentRunLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
}
NSLog(@"completed");
}

- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
NSUserActivity *activity = [[NSUserActivity alloc] initWithActivityType:@"foo"];
activity.title = @"foo title";
activity.eligibleForSearch = YES;
[activity becomeCurrent];
}

- (void)scene:(UIScene *)scene continueUserActivity:(NSUserActivity *)userActivity {
[self synchronizedSystemAPI];
NSLog(@"Continue my other work after system API is complete");
}
@end



Подробнее здесь: https://stackoverflow.com/questions/785 ... onized-api
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «IOS»