Можно ли получить доступ к [UIApplication sharedApplication] из фонового потока?

Во время работы над Objective-C мне нужно получить статус protectedDataAvailable, возможно, внутри некоторых фоновых потоков.

- (BOOL) isProtected {
    BOOL protectedDataAvailable = [[UIApplication sharedApplication] isProtectedDataAvailable];
    return protectedDataAvailable;
}

Поскольку я обращаюсь к [UIApplication sharedApplication], я подозреваю, что блок кода должен запускаться в основной очереди. Как это сделать?

Я думал изменить его, например,

- (BOOL) isProtected {

    BOOL protectedDataAvailable = NO;

    dispatch_sync(dispatch_get_main_queue(), ^{
        protectedDataAvailable = [[UIApplication sharedApplication] isProtectedDataAvailable];
    });

    return protectedDataAvailable;
}

Вопрос 1. Следует ли выполнять код внутри основной очереди/потока пользовательского интерфейса?

Вопрос 2. Если да, решит ли мой измененный код проблему? или есть лучший подход?

Причина, по которой я задаю этот вопрос, заключается в том, что даже если я обращаюсь к UIApplication в основной очереди синхронно, когда блок вызывается из main thread, происходит сбой. Как я могу справиться с этой проблемой?


person Sazzad Hissain Khan    schedule 11.02.2020    source источник


Ответы (1)


Вопрос 1: Следует ли запускать код внутри основной очереди/потока пользовательского интерфейса?

Определенно да, потому что если вы запустите свое приложение с основным средством проверки потока в Xcode, вызовы UIApplication sharedApplication будут выделены как проблемы при доступе из фонового потока.

Вопрос 2: Если да, решит ли мой измененный код проблему?

Если вы не вызовете isProtected из основного потока, да.

или есть лучший подход?

Я бы остановился на чем-то вроде этого:

- (BOOL)isProtected
{
    __block BOOL protectedDataAvailable = NO;

    if ([NSThread isMainThread])
    {
        protectedDataAvailable = [[UIApplication sharedApplication] isProtectedDataAvailable];
    }
    else
    {
        dispatch_sync(dispatch_get_main_queue(), ^{

            protectedDataAvailable = [[UIApplication sharedApplication] isProtectedDataAvailable];
        });
    }

    return protectedDataAvailable;
}

Как указал Алехандро Иван в комментарии, вместо использования семафора вы можете прибегнуть к простому dispatch_sync

person Andrey Chernukha    schedule 11.02.2020
comment
Зачем использовать dispatch_async() с семафором, а не просто dispatch_sync()? Уверен, что обрабатывать семафоры вручную дорого. я бы использовал - (BOOL)isProtected { __block BOOL protectedDataAvailable = NO; dispatch_sync(dispatch_get_main_queue(), ^{ protectedDataAvailable = [[UIApplication sharedApplication] isProtectedDataAvailable]; }); return protectedDataAvailable; } - person Alejandro Iván; 11.02.2020
comment
@ АлехандроИван Я согласен. Просто dispatch_sync определенно является вариантом, по крайней мере, с меньшим количеством кода или даже (в чем я не уверен) с меньшими накладными расходами. - person Andrey Chernukha; 11.02.2020
comment
Основное отличие состоит в том, что очереди GCD не используют блокировки (поэтому они представляют собой доступ к одному потоку), а семафоры используют их (хотя и легкие блокировки мьютекса). Это делает семафоры совместимыми с многопоточностью. Для обычного приложения с пользовательским интерфейсом, вероятно, нет необходимости в семафорах. - person Alejandro Iván; 11.02.2020
comment
@AndreyChernukha Если я использую dispatch_sync, мне просто нужно удалить строки, связанные с семафором, верно? Было бы полезно, если бы вы обновили свой код для использования dispatch_sync. - person Sazzad Hissain Khan; 11.02.2020