2

Apple's Developer Reference mentions that a an object is deallocated if there are no strong reference to it. Can this happen if an instance method called from a weak reference is in the middle of execution?

For example, consider the below snippet -

@interface ExampleObject

- doSomething;

@end


@interface StrongCaller
@property ExampleObject *strong;
@end

@implementation StrongCaller


- initWithExampleInstance:(ExampleObject *) example
{
    _strong = example;
}

- doSomething
{
    ....
    [strong doSomething];
    ....
    strong = nil;
    ....
}

@end

@interface WeakCaller
@property (weak) ExampleObject *weak;
@end 

@implementation WeakCaller

- initWithExampleInstance:(ExampleObject *) example
{
    _weak = example;
}    

- doSomething
{
    ....
    [weak doSomething];
    ....
}

@end

Now, In main thread,

ExampleObject *object = [[ExampleObject alloc] init];

In Thread 1,

[[StrongCaller initWithExampleInstance:object] doSomething];

In Thread2,

[[WeakCaller initWithExampleInstance:object] doSomething];

Assuming that the main thread no longer holds a reference to object, what would happen if strong is set to nil, when [weak doSomething] is executing? Is the object GC'ed in this case?

Gautham J
  • 23
  • 3

1 Answers1

1

Normally this problem happens during asynchronously blocks execution where there is impossible to avoid this problem by changing logic.

But if you are sure that you do not want to change logic you can use the same solution in your case. You should modify your method this way

- (void) doSomething
{
    Your_Class *pointer = self; //Now this local variable keeps strong reference to self
    if(pointer != nil){  // self is not deallocated
        ... your code here
    }
    //Here pointer will be deleted and strong reference will be released automatically 
}
Avt
  • 16,927
  • 4
  • 52
  • 72
  • Thanks for the response. Should this be done for all methods of the soft-referenced object for thread safety, including property accessors? Also, this behaviour seems a bit weird. One would assume ARC to automatically create a strong reference within methods, as the strategy mentioned above. This imposes a number of restrictions on the design. – Gautham J Feb 18 '14 at 15:21
  • Automatic creation of retain/release pair will cause significant drop in performance. So ARC does not do this. Yes, this operation should be done in every method. Automaticaly generated properties could be declared as atomic. – Avt Feb 18 '14 at 15:50
  • As I wrote this mechanism is also used for blocks. You can read about it here http://stackoverflow.com/questions/19018456/ios-blocks-and-strong-weak-references-to-self for example – Avt Feb 18 '14 at 16:00
  • Doesn't this simply move the problem around? What happens if the object is concurrently deallocated just before the strong reference is created on the first line? – Etan Jul 27 '14 at 20:12
  • Update: Tried it out and it still may go boom :-) – Etan Jul 27 '14 at 20:22
  • @Etan I have updated the answer. `if(pointer != nil){` line was added. – Avt Jul 28 '14 at 08:17
  • I'm not sure if this is sufficient. To be honest, I tried with Swift, but it should be the same behavior in Objc. Putting a local variable there produces an implicit "retain" message that is sent to "self". If this message is sent while the object is being deallocated from a different thread, it will be a problem. Could also be a Swift bug in my case as there's no way this can be implemented correctly if there is no internal locking going on that prevents object deallocation during an objc_msg_send call... I even observed that "self" becomes released during the "... your code here" section.. – Etan Jul 28 '14 at 08:30
  • @Etan `retain/release` are thread safe - http://stackoverflow.com/questions/4713533/is-nsobjects-retain-method-atomic . So you should not worry about "If this message (an implicit "retain") is sent while the object is being deallocated from a different thread" – Avt Jul 28 '14 at 10:59