iOS块与同步性

iOS块与同步性,ios,arrays,asynchronous,objective-c-blocks,Ios,Arrays,Asynchronous,Objective C Blocks,我有一个关于我的应用程序中的块和同步性的问题。以下是场景: 我有一个NetworkManager,它使用AFHTTPRequestOperationManager(AFNetworking 2.0)调用服务器。我有一个ContentStore类singleton,它为应用程序提供内容。应用程序中的任何类都可以向content store请求内容,并通过一个块来接收该内容。如果ContentStore在内存或存档中有内容,它会将其从请求内容的类传递到块。如果没有,它将向NetworkManager

我有一个关于我的应用程序中的块和同步性的问题。以下是场景:

我有一个NetworkManager,它使用AFHTTPRequestOperationManager(AFNetworking 2.0)调用服务器。我有一个ContentStore类singleton,它为应用程序提供内容。应用程序中的任何类都可以向content store请求内容,并通过一个块来接收该内容。如果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];

}
@interface ContentStore()
@属性(非原子,强)NSDictionary*downloadDictionary;
@属性(非原子,强)NSMutableArray*下载BlocksForRequest;
@属性(非原子、强)networkManager*networkManager;
@结束
@实现内容存储
-(void)下载WithCompletionBlock:(void(^)(NSDictionary*)completionBlock
{
如果(下载字典){
completionBlock(_downloadDictionary);
返回;
}否则{
_downloadDictionary=[NSKeyedUnarchiveObjectWithFile:[self-downloadArchivePath]];
如果(下载字典){
completionBlock(_downloadDictionary);
返回;
}else if(_downloadBlocksForRequest){
[_downloadsblocksforrequestaddobject:completionBlock];
返回;
}否则{
_downloadBlocksForRequest=[[NSMutableArray alloc]init];
[_downloadsblocksforrequestaddobject:completionBlock];
}
}
void(^downloadCompletionBlock)(NSDictionary*)=^(NSDictionary*downloadDictionary)
{
//做其他必要的工作
[NSKeyedArchiver archiveRootObject:downloadDictionary-toFile:[self-downloadArchivePath]];
[自行设置下载字典:下载字典];

for(int i=0;i
NSMutableArray
)与iOS中的大多数(如果不是全部)可变容器一样,是。因此,您的担心是有道理的,此代码可能会引入一个很难捕获的错误。您可能希望通过执行以下操作来同步对它的访问

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

一种解决方案是BlackRider所说的,使用某种跨线程同步来保护对共享阵列的访问


另一种解决方案是在同一线程(或串行队列)上对阵列执行两项操作(添加到阵列和处理接收到的内容)。这可能需要将“请求内容”操作分派到此线程(或队列)。在您的情况下,这应该没有问题,因为该方法已经是异步的。

谢谢您的快速回复。我明白您的意思。我相信为了使我的代码线程安全并仍然正常工作,我必须将downloadCompletionBlock中的所有代码以及if语句中的所有代码都包含在synchronized中。我不想要任何一个如果数组被循环通过,则执行if语句,如果数组被添加到,则我不希望执行任何downloadCompletionBlock。您同意吗?在不深入具体示例的细节的情况下,将关键部分的大小最小化通常是一个好主意(在这种情况下,
@synchronized
块)。即使在最好的情况下,使用关键部分也会降低代码的执行速度。因此,我会同步
循环,在其中枚举
\u downloadblocksforequest
,以及调用
\u downloadblocksforequest addObject:
。免责声明:我没有花时间理解所有内容你的代码确实如此,所以你是应该同步什么的最佳判断者:)thx,我修改了我的代码以考虑你的评论,一切似乎都很好,我现在感觉更舒服了!太棒了,很高兴我能帮上忙!