3

It it possible to create a locally scoped variable in a method for the lifetime of it's class instance?

I can't use static because it would be shared across all class instances, which is no good. In essence, I want to protect an instance variable by making it so that can only be accessed by one particular method in the class.

I'm thinking this can't really be done, but I thought I'd ask cause it would help a lot.

UPDATE
So, I'm marking @dasblinkenlight's answer as correct (and it is). Although @joshcaswell provided a reference to a better answer in the comments, which is an actual implementation of associative references by Richard J. Ross III. This provides a much easier way of associating a reference without having to dive into the runtime (because he does it for you). If I had found this answer during my original search I wouldn't have asked this question in the first place. But I didn't, so I did.

Why Do this?
I came across an article by Brent Simmons today called Why is Using Associated Objects a Hack?, which directly relates to the question of why I would need to do this in the first place (@bbum & @GabrielePetronella asks this). In my commented discussion with @dasblinkenlight, I explain I want to protect a lazily instantiated iVar from being accessed directly except by it's constructor method. The best way to do this is to hide the iVar from all other class methods so it can only be accessed through it's constructor method. You can, of course, rely on naming conventions (i.e.: _lazyiVar) to remind you not to access it directly, but this is (IMO) a rather fragile form of protection (and I have done this exact thing in the past). Using associated references is a hack and you should question techniques that access the runtime directly, but in this case I prefer the hack as it makes my code that much less likely to crash by protecting my lazily instantiated variables.

Community
  • 1
  • 1
Aaron Hayman
  • 8,492
  • 2
  • 36
  • 63
  • 1
    An instance variable? – bbum Oct 18 '13 at 18:11
  • @bbum *local method scope* – Gabriele Petronella Oct 18 '13 at 18:12
  • @GabrielePetronella Not sure what that buys vs. an instance variable. – bbum Oct 18 '13 at 19:54
  • 1
    @bbum Oh me neither. :D – Gabriele Petronella Oct 18 '13 at 21:29
  • I think this is the same as [ObjC ivar scoped method variables](http://stackoverflow.com/q/11998887), for which a thoroughly clever though rather wild and wooly solution was written by Richard J. Ross III. – jscs Oct 18 '13 at 23:44
  • Your explanation of why you're doing this suggests that you are generally accessing ivars within an object rather than using their accessors. Using accessors exclusively (except in init and dealloc) would save you this trouble by making *all* access to ivars suspicious (and therefore not fragile), rather than trying to remember when it is and is not appropriate. Developing highly consistent coding practice is better than designing complex work-arounds. – Rob Napier Oct 21 '13 at 13:25
  • See "Programming with Objective-C" for Apple's guidance on this: "In general, you should use accessor methods or dot syntax for property access even if you’re accessing an object’s properties from within its own implementation…" https://developer.apple.com/library/ios/documentation/cocoa/conceptual/ProgrammingWithObjectiveC/EncapsulatingData/EncapsulatingData.html – Rob Napier Oct 21 '13 at 13:30
  • Well, that's a little more "Do what I say, not what I do" as Apple's own code tends to be all over the place when it comes to accessing variables. While I don't wish to get into the direct-vs-accessor argument, I will say that my code is consistent in that I only use accessors when I need to. So if I see "self.ivar" in my code, there's a reason (block access, constructor, lazy instantiation, etc). To *me* this is easier to read and I prefer it, but I recognize that others disagree. You are right that it makes lazy iVar a little more tricky, but it's not enough to dissuade my current practice. – Aaron Hayman Oct 21 '13 at 15:02

1 Answers1

4

You are correct, this is not possible: locals cannot outlast the scope in which they are defined. You can add "private"-ish instance variables through class extensions, but these would be accessible to implementations of all methods, not just a single one.

You can also fake addition of instance variables with associative references, but that would require direct interaction with runtime. These references would be accessible to all methods as well, but you can "hide" them by making their static ObjectTagKey local to your method.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • Yeah, using associative references would work, but it's too much for what I'm trying to accomplish. I'm lazily instantiating the variable and thought it would be great if I could *force* other method calls to use the method rather than directly access the variable. – Aaron Hayman Oct 18 '13 at 18:33
  • @AaronHayman If the ivar is in a class extension (i.e. not in the header), the only code that has direct access to it is your own. – Sergey Kalinichenko Oct 18 '13 at 18:48
  • I think you misunderstand. I mean "*force* other methods in the *same* class" to use the constructor method rather than access the iVar directly. This would ensure I don't accidentally access the iVar directly when it hasn't been instantiated (for example, if I come back to the code after a while). All my iVars are listed privately in the `@implementation` unless I absolutely need to make them public... which is very rare. – Aaron Hayman Oct 18 '13 at 19:18
  • @AaronHayman I see. In this case you could give your variable a special name related to the actual name, but also indicating that the variable is initialized lazily. For example, if your variable stores `maxSize`, call the variable `_lazyInitMaxSize`, and use it exclusively in the `maxSize` method. People who maintain your code (including yourself) should be able to guess that they must not access this variable directly. – Sergey Kalinichenko Oct 18 '13 at 19:27