Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <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>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    1. COThats true. Its unwise to override these methods. But since i have in the above code, could you please tell me if i'm wrong or right about the bypassing subclass version of allocWithZone. I was convinced with the book's code and thought you couldnt escape the trap. But it turns out you can. Is it true or not and if so, is the above the code the way to do so.
      singulars
    2. CO" The point is whether an outside caller (main() in your case) can bypass the singleton instantiation, which she cannot. (**)" What you mean to say by this is that without meddling with the pre-existing code (the one that contains subclass ver. of allocWithZone implementation), it is enough to have any kind of external function call go through the "trap" which starts from allocWithZone(subclass ver) and ends at sharedStore method(which returns the singleton).
      singulars
    3. COAlright then, forget about the alloc implementation in my code (comment it up) and then in the main method [[BNRItemStore alloc] init] runs thru the trap. As we would expect. Now,again, if we change it to [[NSObject alloc] init] then it would not go thru the trap.Same goes for something like this in main method- NSAllocateObject([BNRItemStore class], 10, nil). So isnt that an external exploit from an outside method such as main? Coz this time NSObject version of alloc calls the the NSObject's ver of allocWithZone..So isn't this contrary to the book's point??
      singulars
 

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