这是我的代码:
@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 的方法都在同一个线程中执行。但是这段代码按照自己的意愿改变线程,但有时它在单线程中工作。有什么办法可以强制它始终使用同一个线程吗?
一句话,不。除了主队列之外,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
如果您的类有多个实例,则每个新的 init 都会覆盖您的队列。
可以使用单例或静态来解决该问题。
您可以创建一个串行队列并分派到该串行队列,或者将所有工作项分派到主队列。串行队列的优点是队列中的所有工作项都将被一个接一个地处理,因此您不必担心它们之间的同步,但它们也将在每个串行队列的一个线程中运行。
您永远不应该询问您正在哪个线程上运行。如果您将工作项分派到主队列,那么您正在主线程上运行。如果您将工作项分派到串行队列,那么您将在该队列的线程上运行。如果您将工作项分派到并发队列,则无法保证您在哪个线程上运行,并且您不应该关心。