我对我的应用程序中的块和同步性有疑问。这是场景:
我有一个使用AFHTTPRequestOperationManager(AFNetworking 2.0)来调用服务器的NetworkManager。我有一个ContentStore类单例,它为应用程序提供内容。应用程序中的任何类都可以向内容存储库请求内容,并且它传递一个块来接收该内容。如果ContentStore在内存或存档中有内容,它将内容传递给类中要求内容的块。如果没有,它将向NetworkManager发出请求,然后将一个块传递给NetworkManager,当内容从服务器到达时,该块从原始类中调用该块。到目前为止,这一切都很好,并且效果很好。
问题是,有时某个类可以在已经对该内容进行了请求但尚未收到答复时调用ContentStore的内容。在这种情况下,向服务器发送两个请求以获取相同的内容,这实际上并没有引起问题,但是效率很低。
我想出了一个执行以下操作的系统:如果正在向服务器发送内容请求,则ContentStore将传递给它的所有块保存在一个数组中,当从服务器收到答复时,ContentStore循环通过块数组,并将内容传递给每个块。
这很好,但是我想知道是否有可能的故障。当类调用ContentStore获取内容并且正在进行请求时,是否有可能在以下代码中的downloadCompletionBlock循环通过同一数组的同时将一个块添加到该数组?
感谢所有花时间了解和回答我的问题的人。如果您需要更多信息,请告诉我。
@interface ContentStore()
@property (nonatomic, strong) NSDictionary *downloadDictionary;
@property (nonatomic, strong) NSMutableArray *downloadBlocksForRequest;
@property (nonatomic, strong) NetworkManger *networkManager;
@end
@implementation ContentStore
- (void) downloadWithCompletionBlock:(void (^)(NSDictionary *))completionBlock
{
if (_downloadDictionary) {
completionBlock(_downloadDictionary);
return;
} else {
_downloadDictionary = [NSKeyedUnarchiver unarchiveObjectWithFile:[self downloadArchivePath]];
if (_downloadDictionary) {
completionBlock(_downloadDictionary);
return;
} else if (_downloadBlocksForRequest) {
[_downloadBlocksForRequest addObject:completionBlock];
return;
} else {
_downloadBlocksForRequest = [[NSMutableArray alloc]init];
[_downloadBlocksForRequest addObject:completionBlock];
}
}
void (^downloadCompletionBlock)(NSDictionary *) = ^(NSDictionary *downloadDictionary)
{
// do other work necessary
[NSKeyedArchiver archiveRootObject:downloadDictionary toFile:[self downloadArchivePath]];
[self setDownloadDictionary:downloadDictionary];
for (int i=0; i<_facesBlocksForRequest.count; i++) {
void (^complBlock)(NSDictionary *) = [_facesBlocksForRequest objectAtIndex:i];
complBlock(downloadDictionary);
}
_downloadBlocksForRequest = nil;
};
[_networkManager downloadWithCompletionBlock:downloadCompletionBlock];
}
最佳答案
像iOS中大多数(如果不是全部)可变容器一样,NSMutableArray
是not thread-safe。因此,您的担忧是有道理的,并且此代码可能会引入一个非常难以捕获的错误。您可能希望通过执行以下操作来同步对其的访问
@synchronized(_downloadBlocksForRequest) {
// enumerate _downloadBlocksForRequest, or add an object to it, etc.
}