0

What I'm trying to do is following:

Product *product = [fetchResult lastObject];

NSString *productID = product.atProductID;

dispatch_async(queue, ^(void){
// Something with productID like
NSLog(@"productID is %@", productID);
});

Is it safe to do it this way or do I need to create another context for my secondary queue and get the product by its internal ID and then deal with its atProductID attribute?

Update: Well, it reveals that is actually unsafe. One simple solution is to make a copy of a productID string:

Product *product = [fetchResult lastObject];

NSString *productID = [product.atProductID copy];

dispatch_async(queue, ^(void){
// Something with productID like
NSLog(@"productID is %@", productID);
});

This will be safe as you don't keep any references to context or its derivatives on the background thread. The reason for this is that context caches the data it fetched from the persistent store and it itself manages that cache. And no matter if you keep a pointer to that cache or not it may change or destroy it unless it is used on the context's thread.

Danchoys
  • 739
  • 1
  • 8
  • 14

2 Answers2

0

Your code looks fine. You only need a separate managed object context if you are going to do something with it, such as long fetches or changing managed objects.

Also, you can use the variables in the scope of your async block without problem. That's the great advantage of CGD. These threads have contained memory, so I would expect strings to be copied. You can check by logging the pointer address.

Mundi
  • 79,884
  • 17
  • 117
  • 140
  • No, I checked it: GCD doesn't make a copy of variables used inside a block, it just keeps a strong pointer to them to ensure they won't be released before the block finishes execution. – Danchoys Dec 20 '12 at 11:59
  • Ok, welcome to SOF. You need to tick the check mark above. ;-) – Mundi Dec 25 '12 at 21:00
-1

Haven't used dispatch_async before but this code doesn't look healthy to me at all

You are using a variable created in one thread and passing it directly into another code block. Proper way of doing this would be by passing in objects/parameters to the method.

One thing to note, you question is not 100% accurate. When you execute

NSString *productID = product.atProductID;

You are creating a completely new NSString object that has no association to your NSManagedObject (i.e. Product). Thus, your question is rather about passing parameters for dispatch_async and doesn't have much to do with NSManagedObjects

Ege Akpinar
  • 3,266
  • 1
  • 23
  • 29
  • Well you weren't going but you answered my question. :) The question was does it really create a new instance of a NSString when I access the property related to an NSManagedObject attribute or it gives only a reference to it as it is a common behavior within Cocoa. If you could, please give a link where it is stated that NSManagedObject property-accessors perform copy. – Danchoys Dec 20 '12 at 11:34
  • Glad I did :) For future reference, you can do a quick check by assigning product's ID to something else (after NSString initialization) and log both variables (NSString object and attribute) to see if they have same or different values – Ege Akpinar Dec 20 '12 at 11:36
  • No need to pass variables to GCD in the same context. – Mundi Dec 20 '12 at 11:46
  • Hmm, I'm afraid you were wrong and it does return only a reference to a retained string. And I suppose it will continue doing it this way as long as a "retain" modifier is in the corresponding NSManagedObject subclass's property. Here is something about it: http://stackoverflow.com/questions/11411824/how-to-make-nsmanagedobject-nsstring-properties-be-with-copy-instead-of-retai. So the way I did in the example above is error-prone. – Danchoys Dec 20 '12 at 11:46
  • Interesting I wasn't aware of that, thanks. You could possibly try NSMutableString instead, not sure but may work – Ege Akpinar Dec 20 '12 at 11:55