2014-11-08 2 views
4

Вот мой код:Любой способ сделать dispatch_queue_t работать в одном потоке?

@interface MyObject() 
@property(nonatomic) dispatch_queue_t queue; 
@end 

@implementation MyObject { 
    NSThread *_check; 
} 

- (id)init { 
    self = [super init]; 
    if (self) { 
     _queue = dispatch_queue_create("com.Thread.queue", NULL); 
     dispatch_async(_queue, ^{ 
      _check = [NSThread currentThread]; //for ex. thread number = 3 
      //some code here... 
     }); 
    } 

    return self; 
} 

- (void)someMethod:(MyObjClass *)obj { 
    dispatch_async(_queue, ^{ 
     //need th 
     if (_check != [NSThread currentThread]) { // it is sometimes number 3, but sometimes it changes 
      NSLog(@"Thread changed."); 
     } 
     [obj doSmth]; //got crash if currentThread != _check   
    }); 
} 

@end 

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

ответ

6

Одним словом, нет. Помимо основной очереди, GCD не имеет понятия принадлежности к потоку. Если вам действительно нужна привязка к потоку, GCD - это не самый подходящий инструмент. Если вам нравится идиома, и вы хотите «адаптировать» что-то к вашим потребностям, вы можете сделать что-то вроде этого:

@implementation AppDelegate 
{ 
    NSThread* thread; 
} 

void dispatch_thread_async(NSThread* thread, dispatch_block_t block) 
{ 
    if ([NSThread currentThread] == thread) 
    { 
     block(); 
    } 
    else 
    { 
     block = [block copy]; 
     [(id)block performSelector: @selector(invoke) onThread: thread withObject: nil waitUntilDone: NO]; 
    } 
} 

void dispatch_thread_sync(NSThread* thread, dispatch_block_t block) 
{ 
    if ([NSThread currentThread] == thread) 
    { 
     block(); 
    } 
    else 
    { 
     [(id)block performSelector: @selector(invoke) onThread: thread withObject: nil waitUntilDone: YES]; 
    } 
} 

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification 
{ 
    // Insert code here to initialize your application 
    thread = [[NSThread alloc] initWithTarget: self selector:@selector(threadMain) object:nil]; 
    [thread start]; 

    dispatch_thread_async(thread, ^{ 
     NSLog(@"Async Thread: %@", [NSThread currentThread]); 
    }); 

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 
     dispatch_thread_sync(thread, ^{ 
      NSLog(@"Sync Thread: %@", [NSThread currentThread]); 
     }); 
    }); 
} 

- (void)threadMain 
{ 
    // You need the NSPort here because a runloop with no sources or ports registered with it 
    // will simply exit immediately instead of running forever. 
    NSPort* keepAlive = [NSPort port]; 
    NSRunLoop* rl = [NSRunLoop currentRunLoop]; 
    [keepAlive scheduleInRunLoop: rl forMode: NSRunLoopCommonModes]; 
    [rl run]; 
} 

@end 
+0

Thx, это именно то, что я искал. Также стоит упомянуть - он работает на 10% медленнее, чем образец с GCD. – Kirow

+0

Да, GCD довольно оптимизирован. Я удивлен, что штраф составляет * только * 10%. – ipmcc

0

Если у вас есть несколько экземпляров вашего класса, вы перезаписываете свою очередь с каждым новым init.

Для решения проблемы может использоваться одиночный или статический.

+0

Да, вы правы. Но это не проблема, нормально иметь разные потоки для каждого экземпляра. В моем случае я установил ** _ check ** после init, и у меня возникла проблема только в том случае, если '_check! = [NSThread currentThread]'. – Kirow

Смежные вопросы