0

Reference from this post link I implemented a similar category using the same concept of using NSMutableDictionary to store the information I need. But there is one thing confuses me in the original post

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

I know @synchronized keyword is a protection for the mutilthread. but as i go through other examples most of then didn't use the protection. so is the protection necessary? also can i use static dispatch_once_t to replace the @synchronized? below is my code snipptes in .m file

@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];
}
Community
  • 1
  • 1
user1316408
  • 37
  • 1
  • 2
  • 8

2 Answers2

2

Going backwards, no you cannot simply use dispatch_once_t for this particular task. Proper use of dispatch_once_t requires a global variable and your task needs to be done once per object instance - i.e. you would need a unique global for every instance...

Do you need the protection of @synchronized? This is there to prevent two or more threads both creating the dictionary. Without it on the first call from each thread, depending on timing of course, each may return a different dictionary. On subsequent calls each would return the dictionary created by the last thread to make the assignment to the associated variable, all other created dictionaries would be lost.

Important: NSMutableDictionary itself is not thread safe. If you do have multiple threads reading & writing a dictionary then you need additional synchronisation/locking to avoid problems. There are multiple ways to do this, just search and find a solution which fits your needs. Of course if you don't have multiple threads all this is moot, NSMutableDictionary can and is used safely all the time without being thread-safe.

HTH

CRD
  • 52,522
  • 5
  • 70
  • 86
1

Such as it may help to answer the implied concern about locking costs: I notice that you're using OBJC_ASSOCIATION_RETAIN rather than OBJC_ASSOCIATION_RETAIN_NONATOMIC. That would appear to be redundant given your @synchronize in that if you have the latter than you can forego the locking on the former. At the minute you're paying twice for synchronisation. Either pay once or not at all.

The best overall solution might be:

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;

... and stick with OBJC_ASSOCIATION_RETAIN. Also pay attention to CRD's point: mutable dictionaries are not themselves thread safe. So if you actually need thread safety then this doesn't exactly resolve the issue. If you don't need thread safety then switch to OBJC_ASSOCIATION_RETAIN_NONATOMIC and dump the @synchronized.

Tommy
  • 99,986
  • 12
  • 185
  • 204
  • Does this mean that the best overall solution means sticking with both OBJC_ASSOCIATION_RETAIN and the synchronized? Can you elaborate at how is this redundant? And according to @CRD's comment for thread safety for nsmutabledictionary, we would also have to synchronize read/write ? @ property (nonatomic, strong) NSMutableDictionary* associatedDict; is declare in my header file. Thank u both for answering. – user1316408 Jul 02 '15 at 21:15