Any way to make dispatch_queue_t work in one thread?

Here is my code:

@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

I need to make sure that all MyObjClass methods run in the same thread. But this code changes the thread on its own, but sometimes it works on the same thread. Anyway, can I get it to use the same thread all the time?

+4
source share
2 answers

In a word, no. In addition to the main queue, GCD does not have the concept of belonging to a stream. If you really need a thread binding, GCD is not the right tool. If you like the idiom and want to “adapt” something to your needs, you can do something like this:

@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
+7

, init.

.

0

All Articles