6

I have a method that occasionally crashes.

-(void)foo{
    [self doSomething];
    [self.delegate didFinish];
    [self doSomethingElse];
}

-doSomething works correctly, then I call to a delegate -didFinish. Within -didFinish, the reference to this object might be set to nil, releasing it under ARC. When the method crashes, it does so on -doSomethingElse. My assumption was that self would be strong within a method, allowing the function to complete. Is self weak or strong? Is there documentation on this? What would the reasoning be for it being strong or weak?

Edit

Upon being inspired by some of the answers below, I did some investigation. The actual cause of the crash in my case was that the NSNotificationCenter does not retain the observer in any case. Mike Weller indicates below that callers of methods should retain the object while it is being called in order to prevent the case that I described above, however it appears that NSNotificationCenter ignores this issue, and always maintains a weak reference to the observer. In other words:

-(void)setupNotification{
    //observer is weakly referenced when added to NSNotificationCenter
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(handleNotification:)
                                                 name:SomeNotification object:nil];
}

//handle the notification
-(void)handleNotification:(id)notification{
    //owner has reference so this is fine
    [self doSomething];
    //call back to the owner/delegate, owner sets reference to nil
    [self.delegate didFinish];
    //object has been dealloc'ed, crash
    [self doSomethingElse];
}
Saltymule
  • 2,907
  • 2
  • 22
  • 30
  • 2
    If it is `weak` then `self` should become `nil`, and sending message to `nil` won't crash. So I would guess, neither. – kennytm Aug 01 '13 at 14:15
  • Did you use `NSLog` to see what's up with `self.delegate`? – Desdenova Aug 01 '13 at 14:24
  • You should post some more code and your stack trace, also whatever exception or error is occurring. How is the delegate declared? – Nicholas Hart Aug 01 '13 at 14:26
  • I am not interested in debugging the code as it has been fixed already. I am interested in knowing the answer to *this question* similar to what Mike provided below. – Saltymule Aug 01 '13 at 14:53

2 Answers2

10

self would be strong within a method, allowing the function to complete. Is self weak or strong?

self is neither strong nor weak in ARC. It is assumed that the caller holds a reference, and self is unsafe unretained.

It's also true that self can be -dealloced within its own method under ARC, and it's regarded as "Undefined Behavior (or at least dangerous)" for your program to do this.

What would the reasoning be for it being strong or weak?

It's unretained for Performance -- to avoid what is (in the vast majority of cases) an unnecessary reference count inc/dec. Even if they did all those extra ref count operations, your program would still be susceptible to such problems in multithreaded programs or in the presence of a race condition (also UB). So this is one of those extreme edge cases they (rightly) determined they need not defend themselves from.

Is there documentation on this?

Of course! :)

justin
  • 104,054
  • 14
  • 179
  • 226
  • "and it's regarded as "Undefined Behavior (or at least dangerous)" for your program to do this." You're saying, if bad things happen to happen in your program, then it's undefined behavior. Well of course, but that is not useful. How would the programmer know that this could happen? – newacct Aug 04 '13 at 09:14
  • @newacct that's a quote from the linked docs. the purpose of the statement is clear (although i'd have omitted the "at least dangerous" bit). this doesn't happen by chance. it would *seem* by chance until the issue is identified. the purpose of the statement is: when/if your program allows this to happen, regard it as undefined behavior. undefined behavior has a very specific definition in C langs. so the statement serves to specify the severity of this error (if encountered). a programmer who understands their program could identify it during development. crashes and zombies would help, too. – justin Aug 04 '13 at 09:54
  • An object gets deallocated when it no longer has any strong references. The problem is, any method call could potentially cause the last strong reference to the current object to be removed. So under that definition, any method that contains a method call is undefined behavior (unless proven otherwise)? That would make "defined behavior" pretty meaningless. – newacct Aug 04 '13 at 21:32
  • @newacct that's quite an imagination you have -- by your logic, even using memory returned from `malloc` should be UB. no. objective-c is not memory safe; it's a superset of c. ARC is not a garbage collector. judging by your SO account, you should already know these things. – justin Aug 04 '13 at 22:41
  • No, I never said it was memory safe. However, if you follow a correct way to write things then it should be safe, no? I am saying that the fact that `self` is not strong makes it possible for code which is written using correct Objective-C techniques and ARC, to still inadvertently cause `self` to be deallocated in the middle of a method, in a way where you cannot pinpoint any particular part of the code as "wrong". – newacct Aug 04 '13 at 23:01
  • @newacct i happen to agree with their rule used in ARC. in C, C++, and ObjC etc -- using a freed/deleted object is UB and the compiler/runtime won't protect you from this. self being released within a method is a corner case, and will often be apparent if one understands their program's flow. it would also result in many more ref count ops. to make ARC programs highly safe would require much more than we have today. had ARC aimed for this, i expect it would have been a good amount slower than MRC and they should probably just drop interoperability with MRC binaries. (cont) – justin Aug 05 '13 at 16:01
  • (cont) making this specific form safe would have a high cost and would help a very low % of cases. i consider ARC superior to their attempt at ObjC-GC, and i think they have a good balance of safety/speed/compatibility/expectations. so i think the way it is today was a good way to introduce ARC, considering all the code that relies on MRC -- a practical compromise which is compatible with much that is out there. (cont) – justin Aug 05 '13 at 16:02
  • (cont) now, if i were to put on a language designer hat and approach the problem how managed memory *should* be, then i agree with you in that self should not be allowed to be deallocated inside a method. however, if i were to create an implementation to support the safe managed model, i just wouldn't bother maintaining binary compatibility with MRC programs. that's not a light decision to put on decades of code -- i was there for ObjC-GC binary incompatibility; it was a PITA. – justin Aug 05 '13 at 16:04
5

self is neither weak nor strong. If you can access self then you are in the scope of a method call, and that method call is being performed by somebody via a reference they must own. self is implied to be a valid reference as long as it's in scope, and it is implied that any memory management or ownership is handled by the caller.

When calling a method through a weak reference, ARC will retain the object for the duration of that method call (see this answer). With strict compiler warnings enabled, you will actually be forced to create a strong reference before sending any methods to that reference.

So by definition, if a method is being called on an object, the caller must already have ownership and nothing needs to be done.

Of course, it is possible to end up calling methods on deallocated objects but that is the result of bad caller code.

Community
  • 1
  • 1
Mike Weller
  • 45,401
  • 15
  • 131
  • 151
  • "and that method call is being performed by somebody via a reference they must own. self is implied to be a valid reference as long as it's in scope, and it is implied that any memory management or ownership is handled by the caller." However, something you do within this method could inadvertently break the original ownership relation. It is impossible to guarantee in general that `self` will still point to a valid object in the middle of the method. – newacct Aug 02 '13 at 23:01
  • "So by definition, if a method is being called on an object, the caller must already have ownership and nothing needs to be done." Not necessarily. It is only guaranteed that the receiver is valid at the time the call starts; there is no guarantee that it remains valid for the duration of the call. – newacct Aug 04 '13 at 09:10