Note that there are some explanatory texts on larger screens.

plurals
  1. POProper usage of @private variables / properties
    primarykey
    data
    text
    <p>All my research shows that there's no <strong><em>real</em></strong> usage for the <strong>@private</strong> directive - so I must be missing something and need you experts to chime in :-)</p> <p>Assume we have 2 classes: a <strong>Car</strong> class and a <strong>SportsCar</strong> class, where <strong>SportsCar</strong> is a subclass of <strong>Car</strong>. </p> <p>Here's the <strong>Car</strong> class:</p> <pre><code>@interface Car : NSObject { NSString *make; NSString *model; @private int numberOfBackSeatPassengers; // I'm making this a private iVar cause I'm just gonna // say that all Sportscars will be 2-seaters and therefore shouldn't // be able to set/get the number of back-seat passengers } @property (nonatomic, strong) NSString *make, *model; // Now here's my first issue: if I also make "numberOfBackSeatPassengers" an @property // then it seems like all subclasses of this Car class *WILL* be able to access it as // well - even though I declared it as @private - but I'll do this anyway to make my point: @property int numberOfBackSeatPassengers; @end </code></pre> <p>The Implementation looks like this:</p> <pre><code>@implementation Car @synthesize make, model, numberOfBackSeatPassengers; @end </code></pre> <p>Now here's the <strong>Sportscar</strong> class:</p> <pre><code>#import "Car.h" @interface Sportscar : Car @property int turboEngineSize; @end </code></pre> <p>And its implementation:</p> <pre><code>#import "Sportscar.h" @implementation Sportscar @synthesize turboEngineSize; @end </code></pre> <p>In "main" I have this:</p> <pre><code> Car *car1 = [[Car alloc] init]; [car1 setMake:@"Chevy"]; [car1 setModel:@"Impala"]; [car1 setNumberOfBackSeatPassengers:3]; Sportscar *sports1 = [[Sportscar alloc] init]; [sports1 setMake:@"Audi"]; [sports1 setModel:@"tt"]; [sports1 setNumberOfBackSeatPassengers:3]; </code></pre> <p>Obviously I'm able to set the <strong>NumberOfBackSeatPassengers</strong> on the Sportscar - even though that iVar was declared as <strong>@private</strong> - but that's because I made it an <strong>@property</strong> in "Car.h" which means that the synthesized getter and setter for it are Instance Methods, thereby available to <strong><em>all</em></strong> subclasses of <strong>Car</strong>.</p> <p>The other option would have been to NOT declare <strong>numberOfBackSeatPassengers</strong> as an @property in "Car.h", keep it there as only a simple iVar, and instead <em>manually</em> create a Setter and Getter for it in the @implementation of "Car.m" like this:</p> <pre><code>-(void) setNumberOfBackSeatPassengers:(int)numPassgeners { numberOfBackSeatPassengers = numPassgeners; } -(int)numberOfBackSeatPassengers { return numberOfBackSeatPassengers; } </code></pre> <p>This would have made the getter and setter for <strong>numberOfBackSeatPassengers</strong> available only within "Car.m" - which I suppose would make them "private" - but they'd be <strong><em>too</em></strong> private: I could never call them from Main, or from anywhere outside of "Car.m" Moreover, and this is the real point: doing it this way means the @private directive back in "Car.h" doesn't really come into play at all in any of this. I mean I could now go back to "Car.h", take out the "<strong>@private"</strong> directive there -- and my manual setter and getter for <strong>numberOfBackSeatPassengers</strong> would still work exactly the same as they are now, being supposedly private - so what's to be gained with "@private"? How does it truly come into play?</p> <p>Can anyone shed any real light on this?</p> <p>(And yes, I know I can <strong>extend</strong> my Car class in the @interface section of the "Car.m" file - through a category, or make <strong>numberOfBackSeatPassengers</strong> a readonly property first, then change it to readwrite, etc. - but these all seem like workarounds or "hacks" to making "@private" work. I just don't get how @private truly works <em>on its own.</em>) </p> <p>=====================================================</p> <p>EDIT - in response to aroth's comments below:</p> <p>1) aroth's absolutely correct in saying that a subclass could still <em>theoretically</em> call a method that was NOT declared in its parent class's Header -- by using <code>performSelector</code>. I say "theoretically", cause in my case its not quite working <em>correctly</em>: if - in "main" - I call</p> <p><code>[sportscar1 performSelector:@selector(setNumberOfBackSeatPassengers:)];</code></p> <p>then I get some junk number inserted for <code>numberOfBackSeatPassengers</code> cause I can't explicitly pass-in a number as an argument when calling the method this way.</p> <p>(Question: is there a way around this?)</p> <p>2) aroth's also absolutely right in saying that in <code>Sportscar</code> we can simply override the <code>Car</code> class's setter and getter for <code>numberOfBackSeatPassengers</code>, and have these overriding methods reset it to 0, or give an error, etc. But while this is a very practical solution and seems to solve this <em>particular</em> problem, I feel like it doesn't address the larger issue of <code>@private</code> not really seeming to do what it ought to do.</p> <p>3) Redesigning the logic to have a class for <code>FourDoorCar</code> and another one for <code>TwoDoorCar</code> and then continue building off of that is an interesting option - but that almost feels like now Objective-C's syntax is "forcing" itself on my programming logic and how I'm structuring my very project - and this feels like quite an imposition. Maybe I'm wrong and making too much out of this - but either way this all came about just because the <code>@private</code> isn't doing what it seems to promise...? Doesn't feel right.</p> <p>At the end of the day I keep coming back to the same question: what good does <code>@private</code> actually do us? What benefits does it have, what does it "buy" me? It seems that if I want to have an iVar be private, I can just declare it in the ".m" file and not ever bother declaring it in the Header file in the first place. I mean am I right about this or not? or is there still some instance where you'd want to declare an iVar in the Header as <code>@private</code>, but <em>not</em> declare a setter and getter for it there in the Header - so those won't be <em>explicitly</em> available to subclasses - and have it all make sense?</p> <p>Can we think of an actual example for this? Is there some sort of Car property that I'd want to declare as <code>@private</code> <em>in the Header</em> (as opposed to in the ".m") that would somehow benefit me? I thought <code>numberOfBackSeatPassengers</code> would be a good example, but I'm not seeing how it'd really work in action, in actual code...</p> <p>=========================================================================</p> <p>EDIT #2 - Continuing the dialogue with @aroth :-)</p> <p>@aroth - I absolutely agree that its much better/more organized to declare all iVars in the Header and not split things up so that some are in the Header and some are in the Implementation. That creates a mess and I really dislike that approach. (I noted in my original question that I don't want to use the Implementation and/or Category approach to address my question.) -Also, yes, properties absolutely don't always have to be backed up by iVars.</p> <p>-Regarding designing the Class appropriately, I concur that that of course is the key to good programming. The Car/Sportscar example is something I made up on the spot to give my question some context and I didn't invest any time considering its design merits/flaws. I think if we were to take your approach however - which seems quite logical for sure - and go with a Car class, a FourDoorCar subclass, a TwoDoorCar subclass, etc. - we could solve a lot of problems - but its <em>still</em> very likely that sooner or later we'll run into a situation where we'd <em>perhaps</em> want an @private iVar for one of our classes, and not want to create another subclass to deal with it. I mean lets just <em>assume</em> that this would happen, for the sake of this discussion.</p> <p>And so, if possible, I'd really like to think of a specific iVar for our Car class that it would make sense to have as <strong><em>@private</em></strong>, show in code how to use it, and discuss its scope and limitations.</p> <p>I keep trying to think of a real-world example of some property of a Car that we would want only the Car to have - and that none of its subclasses should inherit. I really thought <code>numBackSeatPassengers</code> would do the trick - and for the purposes of our discussion it still can, but, I'll just make up another one and call it <code>phantomIVar</code> :-)</p> <p>And so:</p> <pre><code>@interface Car : NSObject { @private //int numberOfBackSeatPassengers; int phantomIVar; } @property (nonatomic, strong) NSString *make, *model; @end </code></pre> <p>The Implementation would be:</p> <pre><code>@implementation Car @synthesize make, model; -(void) setPhantomIVar:(int)i { phantomIVar = i; } -(int)phantomIVar { return phantomIVar; } @end </code></pre> <p>Which pretty much puts us back where we started :-)</p> <p>At least that's how I feel.</p> <p>I mean the only thing that the <code>@private</code> declaration <em>seems</em> to buy us is <em>readability</em>. So that now, anyone looking at the Header will be able to see that <code>phantomIVar</code> is an iVar of Car, and understand that its private. That's it.</p> <p>In terms of <em>functionality</em> however, it didn't seem to do much. Cause its not like putting <code>@private</code> in front of <code>phantomIVar</code> freed us up to still be able write a setter/getter for it in the Header and have those be only accessible to Car class objects and not subclasses of Car. No, <code>@private</code> doesn't get you that. To get privacy you'd have to go in the Implementation file and write your setter and getter there. And ultimately in Objective-C there's no such thing as private methods. In Obj. C. they're all public. </p> <p>aroth, please let me know if I got this right - and if not, where exactly I went wrong.</p> <p>Many thanks :-)</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.
 

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