Использование потока жизни приложения, отличного от основного потока
У меня есть многопоточное приложение, в котором каждый поток должен выполнять определенную работу, но в определенный момент некоторый код должен выполняться последовательно (например, запись в базу данных sqlite3), поэтому я вызываю этот код для выполнения на главном используя поток:
[self performSelectorOnMainThread:@selector(serialJob:) withObject:object waitUntilDone:YES];
и все шло отлично, за исключением того, что когда этому коду требуется некоторое время, пользовательское взаимодействие с приложением отключается до тех пор, пока этот код не будет завершен, поэтому есть ли способ создать еще один ОДИН поток, который можно запускать в фоновом режиме и вызывать всякий раз, когда Мне нужно это так же, как основной, чтобы я мог заменить предыдущий вызов на:
[self performSelector:@selector(serialJob:) onThread:REQUIRED_THREAD withObject:object waitUntilDone:YES];
этот поток должен быть членом статических данных некоторого класса, к которому должен обращаться весь код.
любая помощь будет очень признательна, и большое спасибо заранее...
3 ответа
Из-за моего вопроса, что мне нужно заблокировать текущий поток, пока работа с базой данных не будет завершена, я попробовал эти два решения, и они отлично работали. Вы можете использовать критические разделы или NSOperationQueue, и я предпочитаю первый, вот код для них обоих:
Определите некоторый класс DatabaseController и добавьте этот код в его реализацию:
static NSString * DatabaseLock = nil;
+ (void)initialize {
[super initialize];
DatabaseLock = [[NSString alloc] initWithString:@"Database-Lock"];
}
+ (NSString *)databaseLock {
return DatabaseLock;
}
- (void)writeToDatabase1 {
@synchronized ([DatabaseController databaseLock]) {
// Code that writes to an sqlite3 database goes here...
}
}
- (void)writeToDatabase2 {
@synchronized ([DatabaseController databaseLock]) {
// Code that writes to an sqlite3 database goes here...
}
}
ИЛИ чтобы использовать NSOperationQueue вы можете использовать:
static NSOperationQueue * DatabaseQueue = nil;
+ (void)initialize {
[super initialize];
DatabaseQueue = [[NSOperationQueue alloc] init];
[DatabaseQueue setMaxConcurrentOperationCount:1];
}
+ (NSOperationQueue *)databaseQueue {
return DatabaseQueue;
}
- (void)writeToDatabase {
NSInvocationOperation * operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(FUNCTION_THAT_WRITES_TO_DATABASE) object:nil];
[operation setQueuePriority:NSOperationQueuePriorityHigh];
[[DatabaseController databaseQueue] addOperations:[NSArray arrayWithObject:operation] waitUntilFinished:YES];
[operation release];
}
Эти два решения блокируют текущий поток до завершения записи в базу данных, что вы можете рассмотреть в большинстве случаев.
Это довольно легко сделать, просто порождайте ваш поток и позволяйте ему запускаться через runloop, используя [[NSRunLoop currentRunLoop] run]
, Это все, что требуется, чтобы иметь возможность использовать performSelector:onThread:
с пользовательской темой.
Если вы используете iOS 4 или новее, вам следует рассмотреть возможность использования очередей Grand Central Dispatch вместо потоков. API GCD намного проще в использовании и могут намного лучше использовать системные ресурсы.
Как говорил Свен, загляните в Grand Central Dispatch.
Вы можете создать очередь следующим образом:
dispatch_queue_t myQueue = dispatch_queue_create("com.yourcompany.myDataQueue", NULL);
Теперь вы можете вызывать блоки в этой очереди:
dispatch_async(myQueue, ^{
// Your code to write to DB.
});
Когда вы закончите, не забудьте освободить очередь:
dispatch_release(myQueue);