我对我的应用程序中的块和同步性有疑问。这是场景:

我有一个使用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中大多数(如果不是全部)可变容器一样,NSMutableArraynot thread-safe。因此,您的担忧是有道理的,并且此代码可能会引入一个非常难以捕获的错误。您可能希望通过执行以下操作来同步对其的访问

@synchronized(_downloadBlocksForRequest) {
     // enumerate _downloadBlocksForRequest, or add an object to it, etc.
}

09-27 18:55