8

I have experience with pure ARC coding. As a compiler feature it honors Objctive-C method family putting right retain/release calls whenever neeeded.

All methods that start with alloc, mutableCopy, copy and new create a new object. They increase the retain count. As a consequence, ARC will release any pointer (and hence the object associated with it) when I no longer need it.

I think that problems could arise when I write methods that do not follow naming conventions. For example, if I write a method like newCustomer that in a first version returns an autoreleased object while in a second version does not, what could happen?

In particular, my questions are the following (they belong to the same reasoning):

  • What happens if the calling and called code are both compiled with ARC?
  • (a) What happens if the calling code is compiled with ARC while the called is compiled with non-ARC?
  • (b) What happens if the calling code is compiled with non-ARC while the called is compiled with ARC?

It would be appreciated an answer that shows how ARC works under the hood (objc_release, objc_retainAutoreleasedReturnValue, etc.).

Thank you in advance.

Lorenzo B
  • 33,216
  • 24
  • 116
  • 190
  • `new` with Objective-C? – ott-- Apr 01 '13 at 16:38
  • @ott-- Sorry, What do you mean? Thanks. – Lorenzo B Apr 01 '13 at 16:39
  • 1
    1) Don't do it. 2) If you ignore (1), I *think* there are some underscore modifiers for the method declaration that can be used to patch things up. – Hot Licks Apr 01 '13 at 16:39
  • @HotLicks Thanks for your comment. I'm aware of those modifiers. But I would like to know why in a) and b) (see edit question for labels) the code will leak and crash respectively. In particular, I would like to know what happens under the hood. Thank you. – Lorenzo B Apr 01 '13 at 16:44
  • There is no method `new`. Are you another PL's addict? – ott-- Apr 01 '13 at 16:49
  • @ott-- It's only an example..What about PL? Thanks. – Lorenzo B Apr 01 '13 at 16:54
  • 2
    @ott yes there is: https://developer.apple.com/library/mac/ipad/#documentation/Cocoa/Reference/Foundation/Classes/NSObject_Class/Reference/Reference.html – Chris Devereux Apr 01 '13 at 16:55
  • Just violate the naming conventions if you have masochistic tendencies … – vikingosegundo Apr 01 '13 at 17:00
  • 1
    Have a look at the blog series http://www.galloway.me.uk/2012/01/a-look-under-arcs-hood-episode-1/, http://www.galloway.me.uk/2012/01/a-look-under-arcs-hood-episode-2/, http://www.galloway.me.uk/2012/02/a-look-under-arcs-hood-episode-3/, http://www.galloway.me.uk/2012/02/a-look-under-arcs-hood-episode-4/, http://www.galloway.me.uk/2012/02/how-does-objc_retainautoreleasedreturnvalue-work/. – Martin R Apr 01 '13 at 17:06
  • @ChrisDevereux You're right, a class method I haven't noticed before. – ott-- Apr 01 '13 at 17:16
  • @vikingosegundo no masochistic tendencies. I'm only curious and SO is the right place to ask. Cheers! – Lorenzo B Apr 01 '13 at 19:25
  • 1
    sure. a valid question to ask. but the easiest way to avoid headaches: stick to the naming conventions. – vikingosegundo Apr 01 '13 at 20:04

2 Answers2

12

A method named newCustomer would fall within the new method family and is thus implicitly marked as returning an retained object. When both calling and called code is compiled with ARC, then ARC balances the extra retain with a release in the caller:

When returning from such a function or method, ARC retains the value at the point of evaluation of the return statement, before leaving all local scopes.

When receiving a return result from such a function or method, ARC releases the value at the end of the full-expression it is contained within, subject to the usual optimizations for local values.

Source

If newCustomer is implemented with manual reference counting and violates the naming convention (i.e., does not return a retained object), then the caller can either over release or under release, depending on the circumstances.

If the caller uses ARC, then the object returned from newCustomer will be overreleased - likely causing the program to crash. This is because the calling code will participate in the second half of the above process, without having had a corresponding retain performed prior to that.

If the calling code is not compiled with ARC, but the called code is (thus correctly implementing returning a retained object), then the behavior depends on the programmer following the naming conventions. If they release the returned value, then the object's reference count will be correctly managed. However, if the programmer believes that their new... method does violate the naming convention, and fails to manually insert a release in the calling code, then the object that was returned will leak.

All in all, as Martin R. points out in the comments, the critical determination is whether the naming conventions are followed in any environment including manual reference counting.

Carl Veazey
  • 18,392
  • 8
  • 66
  • 81
  • 1
    I would formulate the second part slightly different (your answer appeared before I had finished mine :-). In mixed-mode, if the non-ARC code conforms to the naming conventions then everything is OK, otherwise you have over- or under-releases. - In many situations, the static analyzer detects these errors. – Martin R Apr 01 '13 at 16:59
  • Yes, I was specifically addressing the case where newCustomer returns a non retained object. Sorry if I didn't make that clear. – Carl Veazey Apr 01 '13 at 17:05
  • 1
    Further, it would be *very* bad to have a subclass/superclass where a given method in one class returns a retained object while the same method in the other class does not. – Hot Licks Apr 01 '13 at 17:27
2

Just like any other language, when you violate some of the basic assumptions of the language you wander into the area of undefined behavior. At some point in the future, Apple may modify the internals of how -new... does reference counting. It is up to Apple to make sure that code which conforms to the expected use works, but they won't do that for non-conforming uses.

If you need to know what the actual behavior is for a particular version of a compiler running on a particular system, then you must test for it. Don't assume that behavior will be the same for other compilers or versions of the runtime.

In the end, undefined behavior is undefined behavior. When you build code relying on it, you will eventually be affected by a subtle and difficult to diagnose defect.

Jeffery Thomas
  • 42,202
  • 8
  • 92
  • 117