Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>The first, most important lesson here is that you should not override <code>+allocWithZone:</code>. I know the BNR book describes it (and the BNR book is generally very good). You shouldn't do it. I know that Apple includes some example code that does it. You shouldn't do it. (And Apple notes in the explanation that it is rare to need this.) Singletons should be created with the <a href="https://stackoverflow.com/questions/5720029/create-singleton-using-gcds-dispatch-once-in-objective-c"><code>dispatch_once</code> pattern</a>.</p> <p>You don't give the initial code, but I suspect that their example code overrides <code>alloc</code>, but not <code>allocWithZone:</code>. They're simply saying that if the caller uses <code>allocWithZone:</code>, it won't go through <code>alloc</code>, so they've also overridden <code>alloc</code> to catch that. (Of course the right answer would be just to override <code>allocWithZone:</code> and <em>not</em> <code>alloc</code>. But you shouldn't be overriding these methods in any case.)</p> <hr> <p>EDIT:</p> <p>I believe you are misunderstanding what "our sneaky alloc trap" means here. The author is assuming the following code at this point in the text:</p> <pre><code>@interface BNRItemStore : NSObject +(BNRItemStore *)sharedStore; @end @implementation BNRItemStore +(BNRItemStore *)sharedStore{ static BNRItemStore *sharedStore=nil; if (!sharedStore){ sharedStore = [[super allocWithZone:nil] init]; } return sharedStore; } @end </code></pre> <p>That's it; no <code>+alloc</code> overrides at all. It then points out "to enforce the singleton status…you must ensure that another instance of <code>BNRItemStore</code> cannot be allocated." (*)</p> <p>The author goes on to suggest that we might enforce the singleton status by overriding <code>+alloc</code>, but immediately notes that this is insufficient, since the caller can use <code>+allocWithZone:</code> instead. Since it is documented that <code>[NSObject alloc]</code> calls <code>[self allocWithZone:]</code>, it is necessary and sufficient to override <code>+allocWithZone:</code> and unnecessary and insufficient to override <code>+alloc</code>.</p> <p>What you've done in your code is demonstrate that you can modify <code>BNRItemStore</code> to call <code>[super allocWithZone:]</code> in <code>+alloc</code>. That is not the point. If you can modify <code>BNRItemStore</code>, you could also make it a non-singleton. The point is whether an outside caller (<code>main()</code> in your case) can bypass the singleton instantiation, which she cannot. (**)</p> <p>(*) The point it doesn't make at this point, and probably should, is that it is generally a bad idea to "enforce the singleton status" by quietly returning a singleton when the callers asked you to allocate a new object. If you <em>need</em> to enforce the singleton status, it is better IMO to do so with an assertion in <code>init</code>, since the request for a second allocation represents a programming error. That said, there are times when "transparent" singletons of immutable objects can be useful for performance reasons, such as the special singletons <code>NSNumber</code> provides for certain common integers, and this technique is appropriate in those cases. (By "transparent," I mean that the singleton-ness is an implementation detail that the caller should never worry about. This presumes at a minimum that the object is immutable.)</p> <p>(**) Actually she can if she is determined to do so. She could always call <code>NSAllocateObject()</code> herself, bypassing <code>+alloc</code> entirely, and then call <code>-init</code>. This would of course be insane, and there is no reason to "protect" her from herself in doing this. It is not the job of an SDK to protect itself from the caller. It is only the job of an SDK to protect a caller from likely mistakes. The caller is never the enemy.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload