这是数组的延迟加载:
@property (nonatomic, strong) NSArray *dataArray;
- (NSArray *)dataArray {
if (!_dataArray) {
// if array is nil,load data
dispatch_semaphore_t signal = dispatch_semaphore_create(0);
[DataManager loadListSuccess:^(NSArray * _Nonnull list) {
self->_dataArray = list;
dispatch_semaphore_signal(signal);
} failure:^{
dispatch_semaphore_signal(signal);
}];
dispatch_semaphore_wait(signal, DISPATCH_TIME_FOREVER);
return _dataArray;
} else {
return _dataArray;
}
}
我想要的是调用dataArray
的getter方法时,检查它是否为nil。如果为nil,则加载数据,然后返回。如果不是,则直接返回。
下面是加载数据的代码:
+ (void)loadListSuccess:(void (^)(NSArray *list))success failure:(dispatch_block_t)failure {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
success(@[@"1", @"2", @"3"]);
});
}
在viewDidLoad中:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
NSLog(@"viewDidLoad");
NSLog(@"self.dataArray ===== %@", self.dataArray);
NSLog(@"load finish");
}
控制台仅打印 viewDidLoad 。并且所有userInteractionEnabled均已禁用。
但是,如果我将加载数据方法更改为:
+ (void)loadListSuccess:(void (^)(NSArray *list))success failure:(dispatch_block_t)failure {
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)),queue, ^{
success(@[@"1", @"2", @"3"]);
});
}
控制台显示:
- viewDidLoad
- self.dataArray =====( 1, 2, 3 )
- 加载完成
这也是我所期望的。
困扰我的是为什么在主线程中它不起作用?是否有死锁?
答案 0 :(得分:1)
是否有死锁
是的。尽管使用了dispatch_after
(这是异步的),但使用信号量却破坏了异步性,这意味着您正在有效地尝试从主线程同步重新进入主线程。你不能那样做。
答案 1 :(得分:1)
是的,您在主队列上陷入了僵局。在主队列上调用viewDidLoad
。因此,您在主队列上创建了信号灯。
然后在异步调用运行时,在主队列上等待信号量。
问题是您然后尝试在主队列上调用dispatch_after
。但是主队列被阻塞,等待信号量。所以现在您陷入了僵局。
通过将dispatch_after
更改为另一个队列,可以继续进行信号量信号的调用,等待结束,主队列可以继续。
使用信号量时,您始终希望从两个不同的队列中调用signal
和wait
以避免死锁。