NSMutableDictionary不是Threadsafe:那么?

时间:2012-01-17 17:55:26

标签: objective-c ios

我有一个非常很少发生的错误,其中NSMutableDictionary实例中的某个键最终指向错误的对象(同一个字典中的另一个对象)。

“关键混乱”可能是竞争条件的结果吗?

这是代码(因为我已经提出了新的线程安全性):

- (NSNumber*) makeHashFromResizedImage:(UIImage*)original newSize:(CGSize)newSize {
    int retVal = original.hash + newSize.width * 2 + newSize.height * 4;
    return [NSNumber numberWithInteger:retVal];
}

- (UIImage *)resizeImage:(UIImage*)image newSize:(CGSize)newSize {
    NSNumber *key = [self makeHashFromResizedImage:image newSize:newSize];

    if ([self.resizedImages objectForKey:key]) {
        return [self.resizedImages objectForKey:key];
    }

    UIImage *newImage = {{image-resizing-code-here}};

    [self.resizedImages setObject:newImage forKey:key];

    return newImage;
}

注意{{image-resizing-code-here}}已删除,以简洁起见。我开始怀疑我的makeHashFromResizedImage,因为它可能无法按预期工作。现在去单元测试。

3 个答案:

答案 0 :(得分:2)

罗布说;你需要自己提供排除。

是的,“关键混乱”可能是竞争条件的结果,但这种可能性极小。更有可能的是,你最终会发生间歇性崩溃。但是,当然,由于腐败和未定义的行为,错误的价值可能会发生。

答案 1 :(得分:2)

此:

if ([self.resizedImages objectForKey:key]) {
    return [self.resizedImages objectForKey:key];
}

如果另一个名为setObject:forKey:的线程key,第二行的结果将与第一行不同。为什么不将它存储在一个变量中呢?至少你检查的东西和你返回的东西都是一样的。

UIImage* image = [[[[self.resizedImages objectForKey:key] retain] autorelease];
if (image) {
    return image;
}

retain + autorelease只是为了保留image,在此线程运行时不会-dealloc。)

如果您必须确保在函数返回之前不会覆盖与key对应的image,则需要使用锁定,而其他人则应答。


编辑:也许您应该使用UIImage的NSMutableSet。特别是,不要使用哈希值作为键!当两个对象不相同时,哈希值不需要不同。创建一个包含CGSize和UIImage属性的新类X,如果可以多次添加相同的UIImage,则使用X的NSMutableSet。

答案 2 :(得分:-1)

NSMutableDictionary不是线程安全的。由你来提供锁定。