Ответ 1
В основном в этом случае он работает так:
- Вы вызываете fetchUsersWithCompletionHandler: из любого потока, который вам нравится (возможно, основного).
- Он инициализирует NSURLRequest, затем вызывает: dispatch_async (dispatch_get_global_queue... который в основном создает блок и планирует его для обработки в фоновом режиме.
-
Поскольку это dispath_async, текущий поток оставляет метод fetchUsersWithCompletionHandler:.
...
время проходит, пока фоновая очередь не имеет свободных ресурсов
... -
И теперь, когда фоновая очередь бесплатна, он расходует запланированную операцию (Примечание: он выполняет запрос синхронный - так что он ждет данных):
NSURLResponse *response; NSError *error = nil; NSData *receivedData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; ...
-
Как только данные наступят, будет добавлен userArray.
-
Код продолжается до этой части:
if (handler){ dispatch_sync(dispatch_get_main_queue(), ^{ handler(usersArray); }); }
-
Теперь, если мы указали обработчик, он планирует блок для вызова в основной очереди. Это dispatch_sync, поэтому выполнение текущего потока не будет продолжаться до тех пор, пока основной блок не будет выполнен с блоком. На этом этапе фоновый поток терпеливо ждет.
...
еще один минус проходит ... -
Теперь главная очередь имеет несколько свободных ресурсов, поэтому она потребляет выше блока и выполняет этот код (передавая ранее заполненные пользователиArray в обработчик):
handler(usersArray);
-
Как только это будет сделано, он возвращается из блока и продолжает потреблять все, что находится в основной очереди.
- Так как основной поток выполняется с блоком, также может происходить и фоновый поток (застрявший в dispatch_sync). В этом случае он просто возвращается из блока.
Изменить: Что касается вопросов, которые вы задали:
-
Не похоже, что основная/фоновая очередь будет всегда занята, это просто возможно. (предполагая, что фоновая очередь не поддерживает параллельные операции, такие как основной). Представьте следующий код, который выполняется в основном потоке:
dispatch_async(dispatch_get_main_queue(), ^{ //here task #1 that takes 10 seconds to run NSLog(@"Task #1 finished"); }); NSLog(@"Task #1 scheduled"); dispatch_async(dispatch_get_main_queue(), ^{ //here task #2 that takes 5s to run NSLog(@"Task #2 finished"); }); NSLog(@"Task #2 scheduled");
Поскольку оба являются вызовами dispatch_async
, вы планируете их для выполнения один за другим. Но задача № 2 немедленно не будет обрабатываться главной очередью, так как сначала она должна покинуть текущий цикл выполнения, во-вторых, она должна сначала завершить задачу № 1.
Таким образом, вывод журнала будет таким:
Task #1 scheduled
Task #2 scheduled
Task #1 finished
Task #2 finished
2. У вас есть:
typedef void (^Handler)(NSArray *users);
Что объявляет block typedefe'd как Handler
, у которого есть возвращаемый тип void
, и который принимает NSArray *
как параметр.
Позже у вас есть ваша функция:
+(void)fetchUsersWithCompletionHandler:(Handler)handler
Что берется в качестве блока параметров типа Handler
и разрешает доступ к нему с использованием локального имени Handler
.
И шаг № 8:
handler(usersArray);
который непосредственно вызывает блок Handler
(например, вы вызывали какую-либо функцию C/С++) и передает usersArray
в качестве параметра для него.