Синхронизация потока какао при использовании [ALAssetsLibrary enumerateGroupsWithTypes:] - PullRequest
10 голосов
/ 27 августа 2010

Недавно, как и некоторые люди, я обнаружил, что [ALAssetsLibrary enumerateGroupsWithTypes] любит запускать свои блоки в другом потоке. Какой позор, что Apple не задокументировала это: -)

В моих текущих обстоятельствах мне нужно дождаться завершения перечисления, прежде чем основной поток вернет какие-либо результаты. Мне явно нужна какая-то синхронизация потоков.

Я читал о NSLock & NSConditionLock, но пока что кажется, что ничего не соответствует требованию «сигнализировать заблокированному потоку, что этот рабочий поток завершил». Это кажется достаточно простой потребностью - кто-нибудь может указать мне правильное направление?

Ваши подсказки и приветствия, как всегда, приветствуются,

М.

Ответы [ 3 ]

11 голосов
/ 15 июля 2011

Фреймворк не запускает эти блоки в отдельном потоке.Он просто запускает их как дополнительные события в том же цикле выполнения.Чтобы доказать это, попробуйте это

    [library enumerateGroupsWithTypes:ALAssetsGroupAll 
                           usingBlock:[^(ALAssetsGroup * group, BOOL * stop)
                             {
                               if([NSThread isMainThread])
                               {
                                  NSLog(@"main");
                               }
                               else
                               {
                                 NSLog(@"non-main");
                               }
                             } copy] 
           failureBlock:^(NSError * err)
                          {NSLog(@"Erorr: %@", [err localizedDescription] );}];
    [library release];
    if([NSThread isMainThread])
    {
        NSLog(@"main");
    }
    else
    {
        NSLog(@"non-main");
    }

Мой вывод из этого был

main
main
main

Это означает, что блок вызывался в главном потоке.Это просто отдельное событие.Чтобы решить вашу проблему, вам просто нужно как-то вернуть ваше значение изнутри блока, когда вы дойдете до последнего шага.Вы можете сказать, что это последний шаг, потому что ваш блок будет вызываться с nil для объекта группы.

EDIT: например, используйте этот блок

^(ALAssetsGroup * group, BOOL * stop)
{
    if(group == nil)
    {
        // we've enumerated all the groups 
        // do something to return a value somehow (maybe send a selector to a delegate)
    }
}
2 голосов
/ 02 марта 2014

Просто используйте это:

[library enumerateGroupsWithTypes:ALAssetsGroupAll 
                           usingBlock:[^(ALAssetsGroup * group, BOOL * stop)
{
    if(group == nil)
    {
        // this is end of enumeration
    }
}
.
.
.
2 голосов
/ 01 сентября 2010

Ответ заключается в том, чтобы использовать класс NSConditionLock таким образом ...

typedef enum {
    completed = 0,
    running = 1
} threadState;

...

NSConditionLock *lock = [[NSConditionLock alloc] initWithCondition:running];

Затем раскрутите свой поток, или в моем случае вызов [ALAssetsLibrary enumerateGroupsWithTypes:]. Затем заблокируйте родительский поток с помощью этого ...

// Await completion of the worker threads 
[lock lockWhenCondition:completed];
[lock unlockWithCondition:completed];

Когда вся работа будет выполнена в потоке child / worker , разблокируйте родителя этим ...

// Signal the waiting thread
[lock lockWhenCondition:running];
[lock unlockWithCondition:completed];
...