问题在多线程环境中获取正确的属性值

时间:2014-10-01 05:15:11

标签: ios multithreading grand-central-dispatch

我试图在对象初始化期间卸载一些繁重的工作。我已经添加了一个status属性,当我完全初始化了我的对象的所有其他实例变量时,我设置了该属性。我通过以下示例简化了我的整个方法:

这是我的类(Foo),它有我的初始值设定项:

// - 头文件

#import <Foundation/Foundation.h>

typedef void (^loadingCompletionBlock)(BOOL success);

typedef NS_ENUM(NSInteger, FooStatus) {
    FooCreated,
    FooReady,
    FooFailed,
};


@interface Foo : NSObject

+ (id) withCompletionBlock:(loadingCompletionBlock) block;

@property (assign, nonatomic) FooStatus status;

@end

// - 实施文件

@implementation Foo

- (FooStatus) status {

    __block FooStatus readStatus;

    dispatch_sync([Foo concurrentLoadingQueue], ^{
        readStatus = _status;
    });

    return readStatus;
}

+ (dispatch_queue_t)concurrentLoadingQueue
{
    static dispatch_queue_t sharedQueue;
    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{
        sharedQueue = dispatch_queue_create("test.loadingQueue", DISPATCH_QUEUE_CONCURRENT);
    });

    return sharedQueue;
}


+ (id)withCompletionBlock:(loadingCompletionBlock) completed {

    Foo* foo = [[Foo alloc] init];
    foo.status = FooCreated;

    dispatch_async([Foo concurrentLoadingQueue], ^{

        for (int i=0; i<10000; i++)
        {
            NSLog(@"Running long tasks: %d", i);
        }

        foo.status = FooReady;

        completed(YES);

        NSLog(@"Foo status: %d (Background Thread)", foo.status);

    });


    return foo;

};

@end

我在主线程上调用以下代码:

 Foo* foo = [Foo withCompletionBlock:^(BOOL success) {

        dispatch_async(dispatch_get_main_queue(), ^{

             NSLog(@"Foo status: %d (Main Thread)", foo.status);

        });
    }];

    NSLog(@"Foo status: %d (Main Thread)", foo.status);

NSLog会给我这些输出:

2014-10-01 07:09:49.606 TestConcurrentQueue[15610:60b] Foo status: 0 (Main Thread)
2014-10-01 07:09:52.818 TestConcurrentQueue[15610:1303] Running long tasks: 1
2014-10-01 07:09:52.818 TestConcurrentQueue[15610:1303] ......
2014-10-01 07:09:52.818 TestConcurrentQueue[15610:1303] Running long tasks: 9999
2014-10-01 07:09:52.818 TestConcurrentQueue[15610:60b] Foo status: 0 (Main Thread)
2014-10-01 07:09:52.818 TestConcurrentQueue[15610:1303] Foo status: 1 (Background Thread)

0正在创建状态,1为什么我无法在主线程中获得正确的值?

1 个答案:

答案 0 :(得分:1)

我认为foo在完成块中是nil,因为正在创建foo并将其作为原始方法调用的结果进行分配。

一个简单的解决方案是将创建的对象作为参数传递给完成块,以及BOOL

更好的方法可能是使withCompletionBlock:实例方法而不是类方法。然后你的调用代码将是:

Foo* foo = [[Foo alloc] init];
[foo populateWithCompletionBlock:^(BOOL success) {
    dispatch_async(dispatch_get_main_queue(), ^{
         NSLog(@"Foo status: %d (Main Thread)", foo.status);
    });
}];

NSLog(@"Foo status: %d (Main Thread)", foo.status);

这样,完成块内的foo引用了一个实际存在的对象。

init的{​​{1}}方法会设置初始状态,而且全部都是。