使用 dispatch_sync 强制执行顺序
Forcing the order of execution using dispatch_sync
我的库公开了 2 个 API,如下所示:
-(void) createFile{
dispatch_sync(queueSerial, ^{ //B1
[fileObj createFileInfo:file completion:^(NSError *error){
//execute completion block C1
}];
});
}
-(void) readFile:(NSData*)timeStamp{
dispatch_async(queueSerial, ^{ //B2
[fileObj readFileInfo:fileName completion:^(NSError *error) {
dispatch_async(queueSerial2, ^{
//execute completion block C2
});
}]
});
}
readFile
和createFile
都是异步方法。
我通常建议使用我的图书馆的人在 readFile
之前调用 createFile
。但是,无法保证调用者最终将如何实现它。它通常以下列方式被调用(我无法控制这个)
[fileClass createFile];
[fileClass readFile:timeStamp];
我想做的是确保 readFile
在 completion block C1
执行后被调用。我也不想用 createFile
阻塞主线程(但这种期望可以放宽)。所以我想要达到的最终结果是:
- 来电者(我无法控制)调用
createFile
并在调用后立即调用 readFile
createFile
完全执行,完成块 C1
被触发,之后
readFile
被派去完成这件事。
我怎样才能做到这一点?
感觉就像您正在尝试采用现有的基于完成处理程序的 API 并将其塞进串行队列模式中。但是只有当分派的块本身是同步的时,串行队列才有意义。 (并且不要将它与 dispatch_sync
混淆......我们谈论的是块内的任务是否异步,而不是你如何将它分派到你的队列。)但是你正在处理异步方法从其他异步方法调用。
处理采用完成处理程序块的方法时的基本模式是完全消除串行队列(不需要 GCD 队列,或者在任务已经异步时很有用),只使用自己的完成处理程序块方法,并使嵌套最深的块中的最后一次调用调用您自己的完成处理程序。
例如:
- (void)foo:(void (^)())completion {
[fileObj setFileInfo:file completion:^(NSError *error) {
// do some other stuff
completion();
}];
}
- (void)bar:(void (^)())completion {
[fileObj getFileInfo:fileName completion:^(NSError *error) {
// do some other stuff
completion();
}];
}
然后你会这样称呼它:
[self foo:^{
[self bar:^{
// do whatever you want when its all done
}];
}];
这意味着它不会执行任何 getFile
操作,直到 setFile
操作完成。
话虽如此,我想知道您的 setFile
和 getFile
方法在 FileObject
类 自己的方法之外增加了什么附加值。
但关键是在处理异步方法时,你不能简单地用一个简单的串行GCD队列来协调它们。如果你想为本身是异步的任务分配类似行为的行为,那么你通常会考虑使用操作队列(或 promises/futures 或类似的东西)。
我的库公开了 2 个 API,如下所示:
-(void) createFile{
dispatch_sync(queueSerial, ^{ //B1
[fileObj createFileInfo:file completion:^(NSError *error){
//execute completion block C1
}];
});
}
-(void) readFile:(NSData*)timeStamp{
dispatch_async(queueSerial, ^{ //B2
[fileObj readFileInfo:fileName completion:^(NSError *error) {
dispatch_async(queueSerial2, ^{
//execute completion block C2
});
}]
});
}
readFile
和createFile
都是异步方法。
我通常建议使用我的图书馆的人在 readFile
之前调用 createFile
。但是,无法保证调用者最终将如何实现它。它通常以下列方式被调用(我无法控制这个)
[fileClass createFile];
[fileClass readFile:timeStamp];
我想做的是确保 readFile
在 completion block C1
执行后被调用。我也不想用 createFile
阻塞主线程(但这种期望可以放宽)。所以我想要达到的最终结果是:
- 来电者(我无法控制)调用
createFile
并在调用后立即调用readFile
createFile
完全执行,完成块C1
被触发,之后readFile
被派去完成这件事。
我怎样才能做到这一点?
感觉就像您正在尝试采用现有的基于完成处理程序的 API 并将其塞进串行队列模式中。但是只有当分派的块本身是同步的时,串行队列才有意义。 (并且不要将它与 dispatch_sync
混淆......我们谈论的是块内的任务是否异步,而不是你如何将它分派到你的队列。)但是你正在处理异步方法从其他异步方法调用。
处理采用完成处理程序块的方法时的基本模式是完全消除串行队列(不需要 GCD 队列,或者在任务已经异步时很有用),只使用自己的完成处理程序块方法,并使嵌套最深的块中的最后一次调用调用您自己的完成处理程序。
例如:
- (void)foo:(void (^)())completion {
[fileObj setFileInfo:file completion:^(NSError *error) {
// do some other stuff
completion();
}];
}
- (void)bar:(void (^)())completion {
[fileObj getFileInfo:fileName completion:^(NSError *error) {
// do some other stuff
completion();
}];
}
然后你会这样称呼它:
[self foo:^{
[self bar:^{
// do whatever you want when its all done
}];
}];
这意味着它不会执行任何 getFile
操作,直到 setFile
操作完成。
话虽如此,我想知道您的 setFile
和 getFile
方法在 FileObject
类 自己的方法之外增加了什么附加值。
但关键是在处理异步方法时,你不能简单地用一个简单的串行GCD队列来协调它们。如果你想为本身是异步的任务分配类似行为的行为,那么你通常会考虑使用操作队列(或 promises/futures 或类似的东西)。