У меня есть метод вычисления данных (пусть это будет "myMethod:" ), и я хочу переместить вызов в другой поток, потому что я не хочу блокировать основные функции пользовательского интерфейса. Итак, начал делать некоторые исследования о том, как вызвать мой метод в другом потоке. Насколько я вижу, в настоящее время существует много разных способов сделать это. Вот список:
a) используя чистые потоки (доступные с iOS 2.0):
[NSThread detachNewThreadSelector:@selector(myMethod:) toTarget:self withObject:_myParamsArray];
b), используя простой ярлык (доступный с iOS 2.0). Доступно из унаследованного NSObject, но метод также относится к классу NSThread:
[self performSelectorInBackground:@selector(myMethod:) withObject:_myParamsArray];
c) с использованием нового подхода к очередям Grand Central Dispatch (доступно с iOS 4.0):
dispatch_async(dispatch_get_global_queue(0, 0),
^ {
[self myMethod:_myParamsArray];
});
d) каким-то образом, используя некоторые классы, такие как NSOperation, NSBlockOperation или NSOperationQueue, хотя и не уверен, как это сделать (пример будет оценен)
В настоящее время я использовал случай "b", но интересуюсь плюсами и минусами и другими связанными с этим предложениями.
UPDATE: e) также нашел другой способ для выполнения подобных потоков - Run loops. Здесь выдержка из apple docs:
Цикл запуска - это цикл обработки событий, который вы используете для планирования работы и координации получения входящих событий. Цель цикла запуска заключается в том, что ваш поток занят, когда есть работа, и помещайте поток в режим сна, когда его нет.
IMHO, более или менее, вы имеете дело с одной и той же задачей - как вызвать свой метод в отдельном потоке для его асинхронной операции.
UPDATE2: У меня уже был некоторый опыт работы с NSInvocationOperation и NSOperationQueue и IMHO, это довольно удобно. Согласно документам Apple, GCD и NSOperations являются предпочтительным способом реализации многопоточности. Кроме того, NSOperations работает на GCD, начиная с iOS 4.0. Короче говоря, вы создаете экземпляр NSIvocationOperation (как вызов вашего метода), затем создаете NSOperationQueue и добавляете вызов в очередь. NSOperationQueue достаточно умен, вы можете создать экземпляр нескольких объектов NSIvocationOperation (перенос вызовов методов) и их в NSOperationQueue. Остальное гарантировано. NSOperationQueue определяет, сколько параллельных потоков требуется для выполнения вызовов (NSInvocationOperation) и обрабатывает их для вас. Он может выполнить первый вызов в потоке A, затем второй по потоку B, третий по потоку C и дальше по потоку B, так что вам не о чем беспокоиться. Но если вы хотите, вы можете указать, как максимальные потоки NSOperationQueue могут использовать для выполнения вызовов (например, 1), но я не нуждаюсь в этом. По умолчанию все задачи выполняются иначе, чем основной поток, поэтому очереди операций по умолчанию асинхронны. Кроме того, если вы хотите выполнять вызовы методов (каждая из которых завершена в отдельную NSInvocationOperation) в строгой очереди, то вы можете добавлять зависимости, и поэтому NSOperationQueue будет сохранять порядок вызова метода. Вот пример:
// wrap your method call into NSInvocationOperation object
NSInvocationOperation *currentOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(yourMethodCall) object:nil];
// _sharedOperationQueue is a shared NSOperationQueue
// get all executing operations from the queue and get the last operation
_lastOperation = [[_sharedOperationQueue operations] lastObject];
// check if _lastOperation is not nil
if (_lastOperation) {
// if not then add dependency, so the calls would be performed in a queue
[currentOperation addDependency:_lastOperation];
}
// say - execute my method (operation)
[_sharedOperationQueue addOperation:currentOperation];
_lastOperation = currentOperation; // mark as last operation for adding dependency to the next operation
// the queue will retain invocation operation so you will release
[currentOperation release];
..... you can create another NSInvocationOperation and add it to the queue....
Как и для RUNLOOP, иногда вы сталкиваетесь с ними, например, при запуске/планировании таймера или создании соединений NSURL. IMHO, runloop можно сравнить с очередью задач, выполняемых в одном потоке. IMHO runloop - это указатель на поток, который работает как очередь: он имеет задачи, которые могут вызывать события, и они будут помещены в конец очереди в этом потоке. По умолчанию все задачи в вашем приложении выполняются в одной runloop - в одном потоке. Я говорю это указатель, потому что, когда ваше приложение генерирует события, приложение должно знать, где разместить это событие (событие касания или другой обратный вызов делегата) для выполнения. Конечно, вы должны прочитать о runloops для получения более подробной информации, потому что это только мои мысли.