数组在从不同线程枚举时发生变异

时间:2014-07-07 18:13:43

标签: ios arrays multithreading

我有一个与iOs线程安全相关的令人费解的问题。

在单例对象中,我有一个包含字典元素的数组。字典元素包含与等待的资源相关的对象和字符串(从因特网下载的图像)。 当资源可用时(图像完成下载),我从数组中检索等待该特定资源的所有委托。

问题是数组(可变)可以非常频繁地修改(来自不同的线程),并且当它被枚举时它会被修改。

我该如何解决这个问题?我应该创建一个包含可变数组键的静态字典吗?但是仍然可以枚举给定键的特定数组,而某些东西会为它添加另一个值....

这是(非常不是线程安全的)代码:

        - (void)addDelegate:(id<ImageDelegate>)delegate ForFileId:(NSString *)fileId
{
    if (debug) { NSLog(@"[]adding delegate %@ for fileId: %@",delegate,fileId); }
    NSDictionary *d = @{DELEGATE_KEY: delegate,
                        FILE_ID_KEY : fileId};
    [self.delegatesArray addObject:d];
}

- (void)removeDelegate:(id<ImageDelegate>)delegate forImgUrl:(NSString *)imgUrl
{
    NSString *fileId = [Utils formatLink:imgUrl];

    if (debug) { NSLog(@"[]removing delegate %@ for fileId: %@",delegate,fileId); }

    NSDictionary *toRemove;

    for (NSDictionary *crtD in self.delegatesArray) {
        if ([crtD[FILE_ID_KEY] isEqualToString:fileId] && [crtD[DELEGATE_KEY] isEqual:delegate]) {
            toRemove = crtD;
            break;
        }
    }
    [self.delegatesArray removeObject:toRemove];
    if (debug) { NSLog(@"[]removed delegate %@ for fileId: %@",toRemove,fileId); }

}

- (NSArray *)getAllDelegatesForFileId:(NSString *)fileId
{
    NSMutableArray *requiredDelegates = [NSMutableArray new];
    for (NSDictionary *crtD in self.delegatesArray) {
        if ([crtD[FILE_ID_KEY] isEqualToString:fileId]) {
            [requiredDelegates addObject:crtD];
        }
    }
    NSArray *returnedArray = [NSArray arrayWithArray:requiredDelegates];
    if (debug) { NSLog(@"[] found %d delegates for fileId:%@",[returnedArray count],fileId); }
    return returnedArray;
}

1 个答案:

答案 0 :(得分:0)

您有几个选择。

  1. 不要使用快速枚举。使用标准for循环来迭代数组。
  2. 同步对阵列的访问权限,以便一次只能由一个线程使用。
  3. 这样的事情:

    @synchronize (self.delegatesArray) {
        // do something with the array
    }
    

    在数组的每个读/写访问权限周围使用上述内容

    控制访问的另一种(更好的)方法是使用GCD。利用dispatch_syncdispatch_barrier_sync。使用后者围绕写访问,前者围绕读访问。这样做的好处是允许多个读取器,但只允许一个写入器,并且在写入期间不会读取。