Использование потока жизни приложения, отличного от основного потока - PullRequest
2 голосов
/ 13 августа 2011

У меня есть многопоточное приложение, в котором каждый поток должен выполнять определенную работу, но в определенный момент некоторый код должен выполняться последовательно (например, запись в базу данных sqlite3), поэтому я вызываю этот код, чтобывыполняется в главном потоке с использованием:

[self performSelectorOnMainThread:@selector(serialJob:) withObject:object waitUntilDone:YES];

и все идет хорошо, за исключением того, что когда этому коду требуется некоторое время, взаимодействие с приложением пользователя отключается до тех пор, пока этот код не будет завершен, поэтому есть ли способсоздайте еще один ОДИН поток, который можно запускать в фоновом режиме и вызывать всякий раз, когда мне это нужно, точно так же, как основной, чтобы я мог заменить предыдущий вызов на:

[self performSelector:@selector(serialJob:) onThread:REQUIRED_THREAD withObject:object waitUntilDone:YES];

этот поток должен быть членом статических данных некоторого классабыть доступным со всего кода.

любая помощь будет очень признателен, и большое спасибо заранее ...

Ответы [ 3 ]

2 голосов
/ 13 августа 2011

Это довольно легко сделать, просто создайте поток и дайте ему запустить runloop, используя [[NSRunLoop currentRunLoop] run].Это все, что требуется, чтобы иметь возможность использовать performSelector:onThread: с пользовательским потоком.

Если вы используете iOS 4 или более новую версию, вам следует рассмотреть возможность использования очередей Grand Central Dispatch вместо потоков.API GCD намного проще в использовании и могут намного лучше использовать системные ресурсы.

1 голос
/ 13 августа 2011

Как упоминал Свен, посмотрите на 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);
0 голосов
/ 22 августа 2011

Из-за моего вопроса, что мне нужно заблокировать текущий поток, пока работа с базой данных не будет завершена, я попробовал эти два решения, и они отлично работали.Вы можете использовать критические разделы или 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];
}

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

...