【问题标题】:Objective-C runtime associate object with NSMutable dictionaryObjective-C 运行时将对象与 NSMutable 字典关联
【发布时间】:2015-07-02 18:47:01
【问题描述】:

来自这篇文章的参考link 我使用 NSMutableDictionary 存储我需要的信息的相同概念实现了一个类似的类别。但是原帖中有一点让我很困惑

- (NSMutableDictionary *)addl_associatedDictionary
{
     NSMutableDictionary *res = nil;
     @synchronized(self) 
     {
        if (!(res = [self addl_associatedDictionaryPrimitive])) 
        {
           res = [self addl_generateAssociatedDictionary];
        }
     }
    return res;
}

我知道@synchronized 关键字是对多线程的保护。但是当我浏览其他示例时,大多数时候都没有使用保护。那么保护有必要吗?我也可以使用静态 dispatch_once_t 来替换 @synchronized 吗?下面是我在 .m 文件中的代码片段

@dynamic associatedDict;

-(void)setAssociateValue:(NSMutableDictionary*)dict
{
    objc_setAssociatedObject(self, @selector(associatedDict), dict,   OBJC_ASSOCIATION_RETAIN);
} 

-(id)getAssociateValue
{
    return objc_getAssociatedObject(self, @selector(associatedDict));
}

-(NSMutableDictionary*)associatedDict
{
    NSMutableDictionary* dict=[self getAssociateValue];
    if(!dict)
    {
       dict=[[NSMutableDictionary alloc]init];
       [self setAssociatedDict:dict];
    }
    return dict;
 } 


 -(void)setAssociateDict:(NSMutableDictionary *)associatedDict
{
    [self setAssociatedDict:associatedDict];
}

-(id)associate_getObjectForKey:(NSString*)key
{
    return self.associatedDict[key];
}

-(void)associate_setObject:(id)obj forKey:(NSString*)key
{
   [self.associatedDict setObject:obj forKey:key];
}

【问题讨论】:

    标签: ios objective-c concurrency associated-object


    【解决方案1】:

    反过来说,不,你不能简单地使用dispatch_once_t 来完成这个特定的任务。正确使用 dispatch_once_t 需要一个全局变量,并且您的任务需要为每个对象实例执行一次 - 即您需要为每个实例提供一个唯一的全局变量...

    你需要@synchronized的保护吗?这是为了防止两个或多个线程都创建字典。如果在每个线程的第一次调用中没有它,当然取决于时间,每个都可能返回不同的字典。在随后的调用中,每个都将返回由最后一个线程创建的字典以分配给关联的变量,所有其他创建的字典都将丢失。

    重要提示NSMutableDictionary 本身不是线程安全的。如果您确实有多个线程读取和写入字典,那么您需要额外的同步/锁定以避免问题。有多种方法可以做到这一点,只需搜索并找到适合您需求的解决方案。当然,如果您没有多个线程,这一切都没有实际意义,NSMutableDictionary 可以并且一直安全地使用,而不是线程安全的。

    HTH

    【讨论】:

      【解决方案2】:

      这可能有助于回答有关锁定成本的隐含问题:我注意到您使用的是OBJC_ASSOCIATION_RETAIN 而不是OBJC_ASSOCIATION_RETAIN_NONATOMIC。考虑到您的@synchronize,这似乎是多余的,因为如果您拥有后者,那么您可以放弃对前者的锁定。此刻,您要为同步支付两次费用。要么支付一次,要么根本不支付。

      最好的整体解决方案可能是:

      NSMutableDictionary *res; // no need to assign to `nil`; it's implied in ARC
      
      // you're using an atomic property, so this is inherently safe
      if (!(res = [self addl_associatedDictionaryPrimitive])) 
      {
          // okay, doesn't exist, but two or more threads may get to
          // here simultaneously so we'll need to synchronise, and...
          @synchronized(self) 
          {
              // ... check again. As someone else may already have proceeded past the
              // outer if and created it while this thread was waiting to
              // enter the synchronised block. Assuming this dictionary
              // is created more rarely than it's accessed, this is no great issue
              if (!(res = [self addl_associatedDictionaryPrimitive])) 
              {
                 res = [self addl_generateAssociatedDictionary];
              }
          }
      }
      return res;
      

      ...并坚持使用OBJC_ASSOCIATION_RETAIN。还要注意 CRD 的观点:可变字典本身不是线程安全的。因此,如果您确实需要线程安全,那么这并不能完全解决问题。如果您不需要线程安全,请切换到OBJC_ASSOCIATION_RETAIN_NONATOMIC 并转储@synchronized

      【讨论】:

      • 这是否意味着最好的整体解决方案意味着同时使用 OBJC_ASSOCIATION_RETAIN 和同步?你能详细说明这是多余的吗?根据@CRD 对 nsmutabledictionary 线程安全的评论,我们还必须同步读/写吗? @property (nonatomic, strong) NSMutableDictionary* associatedDict;在我的头文件中声明。谢谢你们的回答。
      猜你喜欢
      • 2023-03-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-09
      • 2023-03-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多