Why so many public properties all up in my grizzle?

  • I’ve been developing iOS applications full-time for about 6 months now and
    I love it. I feel pretty strong on the platform now.

    I have a lingering question about something that’s really been bugging the
    heck out of me, though, that I thought I would ask the list and get some
    feedback on.

    It seems to be the case that when people are developing a UIViewController
    subclass or a UIView subclass that they expose *all* the implementation
    details of that class through public properties vs. using ivars.

    Here’s an example. For the purpose of this post, I’ve wrote a simple iPhone
    app with one view. The link below is a screen shot of it:

    https://s3.amazonaws.com/Softwarenerd/MyApp.jpg

    For now, I used Interface Builder to generate the UI.  In doing so, I wound
    up with:

    #import <UIKit/UIKit.h>

    // MyViewController interface.
    @interface MyViewController : UIViewController

    // Properties.
    @property (weak, nonatomic) IBOutlet UILabel * labelMyLabel;

    // buttonDoItTouchUpInside action.
    - (IBAction)buttonDoItTouchUpInside:(id)sender;

    @end

    This means that my UILabel called labelMyLabel is publicly available.
    Anyone who has access to an instance of MyViewController can do anything
    they want to with my label, including replacing it.

    Also, anyone who has an instance of MyViewController can call my
    buttonDoItTouchUpInside action.

    For example, in my AppDelegate, I can do:

    - (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
      self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen]
    bounds]];

      MyViewController * myViewController = [[MyViewController alloc]
    initWithNibName:@"MyViewController" bundle:nil];
      [self setMyViewController:myViewController];
      [[self window] setRootViewController:[self myViewController]];
      [[self window] makeKeyAndVisible];

      // Mess with MyViewController!!!!  HAHAHAHA FU, MyViewController!!!!
      [[myViewController labelMyLabel] setText:@"This is ridiculous!!!!"];
      return YES;
    }

    To me, this totally ridiculous. It breaks well-established rules of
    encapsulation.

    From my analysis, it appears to be nothing more than an artifact of how
    rehydrating NIBs works, and it totally compromises good OO software design
    by leaking all the implementation details of MyViewController to the
    outside world.

    Everyone, all the books, training materials, samples, and so on, just seem
    to accept this style of doing things as being normal. In fact, one book I
    read *encouraged* this technique of using public properties for ALL the
    internal state of a class over using ivars. It said public properties were
    preferable.

    What in the world is the deal with this??  :-)  Can anyone explain this do
    me?

    Building this class without Interface builder, here’s how I coded it:

    // MyViewController implementation.
    @implementation MyViewController
    {
    @private
      UILabel * labelMyLabel_;
      UIButton * buttonDoIt_;
    }

    - (void)viewDidLoad
    {
      [super viewDidLoad];

      [[self view] setBackgroundColor:[UIColor whiteColor]];

      labelMyLabel_ = [[UILabel alloc] initWithFrame:CGRectMake(20.0, 20.0,
    280.0, 21.0)];
      [labelMyLabel_ setText:@"I dare you to press Do It!"];
      [[self view] addSubview:labelMyLabel_];

      buttonDoIt_ = [UIButton buttonWithType:UIButtonTypeRoundedRect];
      [buttonDoIt_ setFrame:CGRectMake(20.0, 49.0, 72.0, 37.0)];
      [buttonDoIt_ setTitle:@"Do It" forState:UIControlStateNormal];
      [buttonDoIt_ addTarget:self action:@selector(buttonDoItTouchUpInside:)
    forControlEvents:UIControlEventTouchUpInside];
      [[self view] addSubview:buttonDoIt_];
    }

    - (void)viewDidUnload
    {
      [super viewDidUnload];
    }

    // buttonDoItTouchUpInside action.
    - (void)buttonDoItTouchUpInside:(id)sender
    {
      [labelMyLabel_ setText:@"You pressed Do It!"];
    }

    @end

    To me, this is how things should be. The implementation details of how my
    view works are hidden.

    Am I missing something?

    @property sure is convenient, but it seems to be misused a lot. A class
    should expose properties that are public, and hide implementation details
    that are not.

    Thanks!

    Brian
  • On Mar 16, 2012, at 2:00 PM, Brian Lambert wrote:

    >
    > To me, this is how things should be. The implementation details of how my
    > view works are hidden.
    >
    > Am I missing something?

    Part of the problem was that prior to Xcode 4, IBOutlets needed to be declared in the header, or Interface Builder wouldn't find them (ditto for IBActions). As such the best you could do was declare the instance variables in the header and pre-pend them with IBOutlet, then declare your properties in a class extension.

    That time has passed now, so you can now completely specify IBOutlets (and IBActions) in your implementation file and hide the details from the outside world. If you want properties, you can use a class extension like so to add them:

    @interface ViewController()

    @property …
    // etc

    @end

    And you can just declare your IBActions on methods that you don't expose to the outside world entirely.
    --
    David Duncan
  • Please don't crosspost. Choose one list.

    --Kyle Sluder
  • > That time has passed now, so you can now completely specify IBOutlets (and IBActions) in your implementation file and hide the details from the outside world. If you want properties, you can use a class extension like so to add them:

    Sorry to hijack this conversation, but I've been meaning to ask: Where is this documented? I stumbled on this feature (and the ability to declare ivars directly in the .m file), but I didn't see it explained it anywhere. I'm sure I'm just not looking in the right place, but I can't find it anywhere.

    Cheers,

    Marco
  • On 3/16/12 2:00 PM, Brian Lambert wrote:
    > This means that my UILabel called labelMyLabel is publicly available.
    > Anyone who has access to an instance of MyViewController can do anything
    > they want to with my label, including replacing it.
    >
    > Also, anyone who has an instance of MyViewController can call my
    > buttonDoItTouchUpInside action.

    In addition to David's remarks, it should also be noted that there isn't
    really any concept of "private" properties or methods (in the enforced
    sense) in Objective-C due to the dynamic nature of the language and
    runtime.  No matter where you *declare* your properties and/or methods,
    what you state above would always be possible.

    (As an aside, major features in Cocoa rely on fairly crazy runtime
    manipulation.  For example, key-value observing:
    http://mikeash.com/pyblog/friday-qa-2009-01-23.html)

    Suppose you wanted to peek under a class' hood (for curiosity's sake, of
    course; private API usage is generally a bad idea and is explicitly
    forbidden in the App Stores and from discussion on the official mailing
    lists).  To see a class' properties (both from itself and its protocols)
    you could try something along the lines of (warning: a thrown together
    quick hack, probably has bugs):

        unsigned int propertyCount;
        objc_property_t *allProperties = class_copyPropertyList([MyClassName
    class], &propertyCount);
        for (NSUInteger i = 0; i < propertyCount; i++) {
            const char *name = property_getName(allProperties[i]);
            NSLog(@"%s", name);
        }

        unsigned int protocolCount;
        Protocol **allProtocols = class_copyProtocolList([MyClassName
    class], &protocolCount);
        for (NSUInteger i = 0; i < protocolCount; i++) {
            const char *protocol = protocol_getName(allProtocols[i]);
            NSLog(@"PROTOCOL %s", protocol);
            unsigned int protoPropertyCount;
            objc_property_t *protoProperties protocol_copyPropertyList(allProtocols[i], &protoPropertyCount);
            for (NSUInteger j = 0; j < protoPropertyCount; j++) {
                const char *propName = property_getName(protoProperties[j]);
                NSLog(@"\t%s", propName);
            }
        }

    This and other fun hackery is documented in the Runtime Programming
    Guide:
    https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Obj
    CRuntimeGuide


    --
    Conrad Shultz

    Synthetiq Solutions
    www.synthetiqsolutions.com
  • David Duncan indicates that some of this can be alleviated with newer runtimes, but Objective C's messaging system allows you to send messages to objects even if those messages are not declared in the object's interface. So simply hiding the actions in the implementation doesn't protect you from finding out the method's name and calling it.

    Another issue (not Obj-C specific) is that all the frameworks that I've used that connect graphically developed UIs with code required the classes to expose the point of connection. Your completely coded example is a little more protected from malicious coders, but not completely, as a hacker would still have access to the controller's view and could walk the subviews making changes. The convenience I get by being able to lay my views out graphically comes at the expense of requiring me to expose my outlets (so that the system can connect my code and my nib). I don't think there could be any way for the system to make those connections without making the outlets publicly available.

    Specific comments on your example, below:

    On Mar 16, 2012, at 2:00 PM, Brian Lambert wrote:

    > #import <UIKit/UIKit.h>
    >
    > // MyViewController interface.
    > @interface MyViewController : UIViewController
    >
    > // Properties.
    > @property (weak, nonatomic) IBOutlet UILabel * labelMyLabel;

    I suspect that the UILabel ought to be strong, but that's not really the topic here.

    > // buttonDoItTouchUpInside action.
    > - (IBAction)buttonDoItTouchUpInside:(id)sender;
    >
    > @end
    >
    > This means that my UILabel called labelMyLabel is publicly available.
    > Anyone who has access to an instance of MyViewController can do anything
    > they want to with my label, including replacing it.

    In your implementation, you (probably) have something like

    @synthesize labelMyLabel=_labelMyLabel;

    This means that labelMyLabel may be public but the actual data _labelMyLabel is private. If you are really concerned about someone tinkering with the labelMyLabel, you can try to intercept access to labelMyLabel by implementing your own custom getter/setter. But if you want the runtime to connect your label to your class, you are going to need to allow outsiders to set your label at some point (possibly repeatedly as your view unloads and loads due to memory warnings).

    > Also, anyone who has an instance of MyViewController can call my
    > buttonDoItTouchUpInside action.

    If you don't want to expose this, then you can expose the button through a IBOutlet and manually connect the action in viewDidLoad. I actually prefer to connect actions manually because then if I have multiple nibs for the same class (e.g., an iPhone and an iPad nib for the same controller), I don't have to try to remember to set all the actions, just the outlets.

    > Everyone, all the books, training materials, samples, and so on, just seem
    > to accept this style of doing things as being normal. In fact, one book I
    > read *encouraged* this technique of using public properties for ALL the
    > internal state of a class over using ivars. It said public properties were
    > preferable.

    The ivars are your data, the properties are just getter/setter methods that access that data (with some syntactic sugar that makes it look like data access). I would guess that the author was suggesting to make all data access go through getter/setter properties instead of direct ivar access. I think they were comparing "public property vs. public ivar" and proposing the use of public properties (getter/setters) instead of direct data manipulation.

    Aaron
  • On Mar 16, 2012, at 2:57 PM, Eeyore wrote:

    > So simply hiding the actions in the implementation doesn't protect you from finding out the method's name and calling it.

    Well, sure. If you’re in the same process, there’s nothing protecting you from malicious code. The same goes for C++ or assembly; it’s just a little easier to find the method’s entry point in Obj-C because there’s more metadata.

    The point of not declaring internal methods in the header isn’t for security, it’s to prevent accidentally using internal APIs in places where you shouldn’t. If a class considers property X as part of its internal state, then other code in the project shouldn’t use X, so you want to make sure that accidentally referring to X produces a compile error.

    —Jens
  • On Mar 16, 2012, at 6:53 PM, <cocoa-dev-request...> wrote:

    > Date: Fri, 16 Mar 2012 15:53:30 -0700
    > From: Jens Alfke <jens...>
    > To: Eeyore <eeyore...>
    > Cc: cocoa-dev list <cocoa-dev...>
    > Subject: Re: Why so many public properties all up in my grizzle?
    > Message-ID: <4ABA472F-CDAD-47F3-8544-A5538F5AC2A6...>
    > Content-Type: text/plain;    charset=windows-1252
    >
    >
    > On Mar 16, 2012, at 2:57 PM, Eeyore wrote:
    >
    >> So simply hiding the actions in the implementation doesn't protect you from finding out the method's name and calling it.
    >
    > Well, sure. If you’re in the same process, there’s nothing protecting you from malicious code. The same goes for C++ or assembly; it’s just a little easier to find the method’s entry point in Obj-C because there’s more metadata.

    ... and of course, even not in the case of hackers who are wanting to do malicious things, if any curious party can get the compiled code, they can take the time to reverse engineer it from assembly. IMO, it's generally a waste of time to try to spend too much time "hiding" things, because they're all hanging out there in the compiled code anyway :-)

    -gt
  • A few points worth clarifying for the original poster here ...

    Using a @property does NOT actually expose the underlying implementation.
    @properties are like configurable ACCESSORS ... they do *NOT* necessarily
    provide direct access to the implementation. You can implement them however
    you want. You can @synthesize them, make them readonly, return something
    computed from them ... or do all sorts of work when trying to "set" them.

    It is really up to you to be careful what you decide to expose. Consider
    that in Java, one must often write

        public void setName(String name) { this.name = name; }
        public String getName() { return this.name}

    @properties can give you this type of behavior in a 'declaratory' way. They
    are actually very powerful as this is only *one* example of how they can be
    used. Consider attributes such as assign, readonly, atomic ... there are
    loads of semantics that you can apply to your accessors by changing just a
    few words in one line:

        @property (readonly) NSString *name;

    Dig into them here.<http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Obje
    ctiveC/Chapters/ocProperties.html
    >
    They
    are more than just a convenience. They are succinct. They are
    self-describing. If used correctly - they are very very consistent with
    standard OO practices. You can think of them as syntactic sugar for
    well-known and used OO patterns - but some would suggest they are much more
    powerful than that.

    And with respect to your original IB implementation, note that Interface
    Builder can bind to ivars that are not formally declared as @property. For
    example, you may do this:

        @interface MyViewController {
            @private
                IBOutlet UILabel *labelMyLabel;
                IBOutlet UIButton *buttonDoIt;
        }

    The ivars are not exposed, IB finds them ... all is well - and the code
    looks more or less like any other OO language that declares the ivars in
    the headers. Now, whether or not THAT is a good practice is a different
    debate and has implications far beyond the scope of Objective-C or Cocoa
    for that matter (ie: declaring ivars in the implementation files).

    Security and runtime implications aside, you can write excellent OO code
    with a liberal use of @properties in Objective-C but as Bjarne once
    said<http://www2.research.att.com/~bs/bs_faq.html#really-say-that>:
    "*C makes it easy to shoot yourself in the foot; C++ makes it harder, but
    when you do it blows your whole leg off" *and likewise, @properties can be
    abused if not understood or used incorrectly.

    Hope that helps,
    -Luther

    On Fri, Mar 16, 2012 at 5:53 PM, Jens Alfke <jens...> wrote:

    >
    > On Mar 16, 2012, at 2:57 PM, Eeyore wrote:
    >
    >> So simply hiding the actions in the implementation doesn't protect you
    > from finding out the method's name and calling it.
    >
    > Well, sure. If you’re in the same process, there’s nothing protecting you
    > from malicious code. The same goes for C++ or assembly; it’s just a little
    > easier to find the method’s entry point in Obj-C because there’s more
    > metadata.
    >
    > The point of not declaring internal methods in the header isn’t for
    > security, it’s to prevent accidentally using internal APIs in places where
    > you shouldn’t. If a class considers property X as part of its internal
    > state, then other code in the project shouldn’t use X, so you want to make
    > sure that accidentally referring to X produces a compile error.
    >
    > —Jens
    >
  • This is an interesting discussion, but there is a lot of misunderstanding of the concept of information hiding if not in what has been said here, but generally in the industry. This term was introduced by David Parnas, and I think it is a bit unfortunate because if you read his papers on this he really means implementation hiding:

    On the Criteria to be used in Decomposing Systems into Modules (1972):

    http://www-sst.informatik.tu-cottbus.de/~db/doc/People/Broy/Software-Pionee
    rs/Parnas_hist.pdf


    The Secret History of Information Hiding (2002):

    http://www-sst.informatik.tu-cottbus.de/~db/doc/People/Broy/Software-Pionee
    rs/Parnas_new.pdf


    There is something deeper to this than simply hiding variables. A lot of people using C++, Java, etc think it means hiding data behind get and set routines. However, in reality we are trying to expose data, we are just trying to do it in an implementation independent manner. Thus it is the interface (API) is the important part of the design.

    A corollary of this is Bertrand Meyer's Principle of Uniform Access, which says values should be provided to a caller in a uniform way, no matter whether the data comes from storage (variable), is computed either in an expression or a function:

    http://en.wikipedia.org/wiki/Uniform_access_principle

    http://martinfowler.com/bliki/UniformAccessPrinciple.html

    I think Martin Fowler's article clearly shows Parnas's ideas.

    Objective-C implements this principle of uniform access with properties.

    Ian

    On 17 Mar 2012, at 08:56, Conrad Shultz wrote:

    > On 3/16/12 2:00 PM, Brian Lambert wrote:
    >> This means that my UILabel called labelMyLabel is publicly available.
    >> Anyone who has access to an instance of MyViewController can do anything
    >> they want to with my label, including replacing it.
    >>
    >> Also, anyone who has an instance of MyViewController can call my
    >> buttonDoItTouchUpInside action.
    >
    > In addition to David's remarks, it should also be noted that there isn't
    > really any concept of "private" properties or methods (in the enforced
    > sense) in Objective-C due to the dynamic nature of the language and
    > runtime.  No matter where you *declare* your properties and/or methods,
    > what you state above would always be possible.
    >
    > (As an aside, major features in Cocoa rely on fairly crazy runtime
    > manipulation.  For example, key-value observing:
    > http://mikeash.com/pyblog/friday-qa-2009-01-23.html)
    >
    > Suppose you wanted to peek under a class' hood (for curiosity's sake, of
    > course; private API usage is generally a bad idea and is explicitly
    > forbidden in the App Stores and from discussion on the official mailing
    > lists).  To see a class' properties (both from itself and its protocols)
    > you could try something along the lines of (warning: a thrown together
    > quick hack, probably has bugs):
    >
    > unsigned int propertyCount;
    > objc_property_t *allProperties = class_copyPropertyList([MyClassName
    > class], &propertyCount);
    > for (NSUInteger i = 0; i < propertyCount; i++) {
    > const char *name = property_getName(allProperties[i]);
    > NSLog(@"%s", name);
    > }
    >
    > unsigned int protocolCount;
    > Protocol **allProtocols = class_copyProtocolList([MyClassName
    > class], &protocolCount);
    > for (NSUInteger i = 0; i < protocolCount; i++) {
    > const char *protocol = protocol_getName(allProtocols[i]);
    > NSLog(@"PROTOCOL %s", protocol);
    > unsigned int protoPropertyCount;
    > objc_property_t *protoProperties > protocol_copyPropertyList(allProtocols[i], &protoPropertyCount);
    > for (NSUInteger j = 0; j < protoPropertyCount; j++) {
    > const char *propName = property_getName(protoProperties[j]);
    > NSLog(@"\t%s", propName);
    > }
    > }
    >
    > This and other fun hackery is documented in the Runtime Programming
    > Guide:
    > https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Obj
    CRuntimeGuide

    >
    >
    >
    > --
    > Conrad Shultz
    >
    > Synthetiq Solutions
    > www.synthetiqsolutions.com
  • Thanks for asking this, Brian.  I've wondered the same thing, and in fact I
    went through my code and removed almost all property declarations from my
    view controllers.  Since most properties are declared as "retain", you're
    just increasing your bookkeeping to avoid leaks.  Not to mention the sheer
    maintenance hassle of typing out or deleting the declarations as you add or
    remove members.

    And as someone pointed out, properties are not at all necessary for making
    connections in IB.  So I don't see the point.  Now I'm referring to the
    members directly, with the added bonus of being able to use member notation
    to identify members for clarity.

    Regards,
    Gavin
  • On Mar 16, 2012, at 9:16 PM, G S wrote:

    > Thanks for asking this, Brian.  I've wondered the same thing, and in fact I
    > went through my code and removed almost all property declarations from my
    > view controllers.  Since most properties are declared as "retain", you're
    > just increasing your bookkeeping to avoid leaks.  Not to mention the sheer
    > maintenance hassle of typing out or deleting the declarations as you add or
    > remove members.
    >
    > And as someone pointed out, properties are not at all necessary for making
    > connections in IB.  So I don't see the point.  Now I'm referring to the
    > members directly, with the added bonus of being able to use member notation
    > to identify members for clarity.

    This pattern is pretty questionable though in terms of OO — you have one class (NSNib, UINib, etc.) directly setting instance variables in another class (your view controller) and using runtime functions to hack around things like @private. That’s really icky — using properties seems like a much cleaner way to do it. The property can be declared in a class extension in the .m file, and it’s not like typing

    @property IBOutlet NSButton *foo;

    is that much harder than typing

    {
    @private
        IBOutlet NSButton *_foo;
    }

    when it comes down to it.

    Charles
  • >
    > This pattern is pretty questionable though in terms of OO — you have one
    > class (NSNib, UINib, etc.) directly setting instance variables in another
    > class (your view controller) and using runtime functions to hack around
    > things like @private.
    >

    How do you figure?  I'm not doing any manipulation of non-property members
    between classes.  If you're saying that Cocoa does it when loading from a
    nib, then it's doing that anyway; properties aren't required for that
    action.  From the end-user (end-programmer) perspective, I don't see any
    bad OO going on here.
  • On Mar 17, 2012, at 3:45 AM, G S wrote:

    > This pattern is pretty questionable though in terms of OO — you have one class (NSNib, UINib, etc.) directly setting instance variables in another class (your view controller) and using runtime functions to hack around things like @private.
    >
    > How do you figure?  I'm not doing any manipulation of non-property members between classes.  If you're saying that Cocoa does it when loading from a nib, then it's doing that anyway; properties aren't required for that action.  From the end-user (end-programmer) perspective, I don't see any bad OO going on here.

    So you have an ivar marked @private. How do you think that (NS)|(UI)Nib — an unrelated class that shouldn’t have access to your private ivars — sets the outlet variables to your nib objects? It does it via runtime hackery. If you declare a property, on the other hand, it just calls the setter. Much cleaner and more OO, if you ask me.

    Charles
  • >
    > How do you think that (NS)|(UI)Nib — an unrelated class that shouldn’t
    > have access to your private ivars — sets the outlet variables to your nib
    > objects? It does it via runtime hackery. If you declare a property, on the
    > other hand, it just calls the setter. Much cleaner and more OO, if you ask
    > me.
    >

    Interesting.  I went and read up on NSNib and learned some stuff, so thanks
    for the reference.

    That kind of behind-the-scenes stuff really doesn't worry me too much,
    since there are all kinds of hacky, non-OO things taking place in this
    language.  I'm not denigrating you for trying to avoid as much of it as
    possible, but it seems like there's more of it going on than one can
    practically prevent.
  • On Mar 17, 2012, at 6:47 AM, G S wrote:

    > That kind of behind-the-scenes stuff really doesn't worry me too much, since there are all kinds of hacky, non-OO things taking place in this language.  I'm not denigrating you for trying to avoid as much of it as possible, but it seems like there's more of it going on than one can practically prevent.

    Other than the awful misfeature of KVO accessing ivars directly, which I also recommend against using, I can’t think of too many other examples of a class monkeying with another class’s private instance variables off the top of my head.

    Charles
  • On Sat, 17 Mar 2012 01:45:33 -0700, G S <stokestack...> said:
    >>
    >> This pattern is pretty questionable though in terms of OO — you have one
    >> class (NSNib, UINib, etc.) directly setting instance variables in another
    >> class (your view controller) and using runtime functions to hack around
    >> things like @private.
    >>
    >
    > How do you figure?  I'm not doing any manipulation of non-property members
    > between classes.  If you're saying that Cocoa does it when loading from a
    > nib, then it's doing that anyway; properties aren't required for that
    > action.  From the end-user (end-programmer) perspective, I don't see any
    > bad OO going on here.

    So we're talking about just declaring an IBOutlet ivar and letting the nib set it via KVC (in iOS)? The problem with that is that before ARC you could really mess yourself up with that pattern, as there is an **implicit retain** performed by KVC when it access an ivar directly, which you're not told about and which may not be at all what you want.

    So you've got this:

    IBOutlet MyClass* myIvar;

    ...just sitting there, with *no* retain policy declaration and thus nothing to remind you that you need to release that ivar in your dealloc or it's going to leak.

    For all the faults of @property declarations (well discussed in a different thread on this list), they are certainly helpful for reminding you, the programmer, how memory is supposed to be managed thru the accessor. And before ARC you could say this:

    @property (nonatomic, assign) MyClass* myIvar;

    ...and synthesize the accessors, and by jingo this would actually *be* an assign-policy setter (no retain), which, for something loaded from a nib, is very often what you want. So the property declaration actually **guards against KVC interfering with your memory management**.

    Therefore, my current pattern is to declare my nonpublic properties in a class extension in the .m file. This is so common that in Xcode 4.3 the iOS project templates actually give you a class extension in the .m file so you can do that - though, to be sure, the templates do some other memory management stuff that I don't agree with.

    Now, of course with ARC things are greatly simplified, and they're going to be simplified even more when synthesis of accessors is the default. Also I wish nonatomic were the default, but that's another story I suppose... m.

    --
    matt neuburg, phd = <matt...>, <http://www.apeth.net/matt/>
    A fool + a tool + an autorelease pool = cool!
    Programming iOS 5! http://shop.oreilly.com/product/0636920023562.do
  • On Fri, 16 Mar 2012 17:11:24 -0400, Marco Tabini <mtabini...> said:
    >> That time has passed now, so you can now completely specify IBOutlets (and IBActions) in your implementation file and hide the details from the outside world. If you want properties, you can use a class extension like so to add them:
    >
    > Sorry to hijack this conversation, but I've been meaning to ask: Where is this documented? I stumbled on this feature (and the ability to declare ivars directly in the .m file), but I didn't see it explained it anywhere. I'm sure I'm just not looking in the right place, but I can't find it anywhere.

    See Apple's document "The Objective-C Programming Language".

    In the chapter called "Defining a Class", not only is declaring an ivar in the .m file covered, but doing it in the .h file is downright discouraged (rightly so). In practice, this feature of Objective-C did not swim into most people's ken until Xcode 4.2, when LLVM because the default compiler.

    In the chapter called "Categories and Extensions", declaration of private properties is discussed. That feature is considerably older.

    m.

    PS And of course there's also my book, which makes much of these features.

    PPS The trouble with language improvements like this, and with documents like The Objective-C Programming Language, is that there's a terminus point somewhere and they don't tell you exactly when it is. What I mean is, you can surprise yourself by adopting an improvement of this sort and then opening your project in an earlier version of Xcode that doesn't understand it. Also, different *parts* of Xcode may not understand it; for example, your code will compile, but the feature where you can drag from an ivar to the nib editor to form an outlet might not work (though now, I believe, it does).

    --
    matt neuburg, phd = <matt...>, <http://www.apeth.net/matt/>
    A fool + a tool + an autorelease pool = cool!
    Programming iOS 5! http://shop.oreilly.com/product/0636920023562.do
  • I'd like an argument, please.

    Regarding this:

        In the chapter called "Defining a Class", not only is declaring
        an ivar in the .m file covered, but doing it in the .h file is downright
        discouraged (rightly so). In practice, this feature of Objective-C...

    I can't stand thus sort of subtle crap.  If it's legal to declare ivars in
    the .M file and the .H file, it's crap to say it's "discouraged" in the .H
    file.  Either a language is well-designed, consistent, and carefully
    thought out, or, it has turned into crap.

    Is there a warning level for "You did something that's totally legal, but,
    discouraged."?

    ivars in the .H file are totally necessary in order to use ivars with
    Objective-C Category files.  I love Objective-C Category files because they
    allow me to segment my implementation such that each file more or less
    represents each interface that my class implements, vs, loading *all* the
    implementation details into one .M file simply so I don't have to declare
    ivars in the .H file.

    I get why ivars in the .H file is not super fantastic, so let's not have
    that debate.

    Is there a way to declare ivars in the .M file AND have them accessible
    from Objective-C Category files for the class?

    Thanks!

    Brian

    On Mon, Mar 19, 2012 at 11:32 AM, Matt Neuburg <matt...> wrote:

    > On Fri, 16 Mar 2012 17:11:24 -0400, Marco Tabini <mtabini...> said:
    >>> That time has passed now, so you can now completely specify IBOutlets
    > (and IBActions) in your implementation file and hide the details from the
    > outside world. If you want properties, you can use a class extension like
    > so to add them:
    >>
    >> Sorry to hijack this conversation, but I've been meaning to ask: Where is
    > this documented? I stumbled on this feature (and the ability to declare
    > ivars directly in the .m file), but I didn't see it explained it anywhere.
    > I'm sure I'm just not looking in the right place, but I can't find it
    > anywhere.
    >
    > See Apple's document "The Objective-C Programming Language".
    >
    > In the chapter called "Defining a Class", not only is declaring an ivar in
    > the .m file covered, but doing it in the .h file is downright discouraged
    > (rightly so). In practice, this feature of Objective-C did not swim into
    > most people's ken until Xcode 4.2, when LLVM because the default compiler.
    >
    > In the chapter called "Categories and Extensions", declaration of private
    > properties is discussed. That feature is considerably older.
    >
    > m.
    >
    > PS And of course there's also my book, which makes much of these features.
    >
    > PPS The trouble with language improvements like this, and with documents
    > like The Objective-C Programming Language, is that there's a terminus point
    > somewhere and they don't tell you exactly when it is. What I mean is, you
    > can surprise yourself by adopting an improvement of this sort and then
    > opening your project in an earlier version of Xcode that doesn't understand
    > it. Also, different *parts* of Xcode may not understand it; for example,
    > your code will compile, but the feature where you can drag from an ivar to
    > the nib editor to form an outlet might not work (though now, I believe, it
    > does).
    >
    > --
    > matt neuburg, phd = <matt...>, <http://www.apeth.net/matt/>
    > A fool + a tool + an autorelease pool = cool!
    > Programming iOS 5! http://shop.oreilly.com/product/0636920023562.do
    >
  • One final note:

    ivars in the .H file of a public framework is *obviously stupid* as it
    leaks implementation details.

    ivars in the .H file of my Foo class, which no one other than me will ever
    use, should be relatively OK.  After all, I'm not trying to prevent myself
    from knowing anything about my implementation of Foo.  I'm just trying to
    ensure that my *intent* for my class is well-understood to other
    programmers who will work on Foo in the future.

    On Mon, Mar 19, 2012 at 12:27 PM, Brian Lambert <brianlambert...>wrote:

    > I'd like an argument, please.
    >
    > Regarding this:
    >
    > In the chapter called "Defining a Class", not only is declaring
    > an ivar in the .m file covered, but doing it in the .h file is
    > downright
    > discouraged (rightly so). In practice, this feature of Objective-C...
    >
    > I can't stand thus sort of subtle crap.  If it's legal to declare ivars in
    > the .M file and the .H file, it's crap to say it's "discouraged" in the .H
    > file.  Either a language is well-designed, consistent, and carefully
    > thought out, or, it has turned into crap.
    >
    > Is there a warning level for "You did something that's totally legal, but,
    > discouraged."?
    >
    > ivars in the .H file are totally necessary in order to use ivars with
    > Objective-C Category files.  I love Objective-C Category files because they
    > allow me to segment my implementation such that each file more or less
    > represents each interface that my class implements, vs, loading *all* the
    > implementation details into one .M file simply so I don't have to declare
    > ivars in the .H file.
    >
    > I get why ivars in the .H file is not super fantastic, so let's not have
    > that debate.
    >
    > Is there a way to declare ivars in the .M file AND have them accessible
    > from Objective-C Category files for the class?
    >
    > Thanks!
    >
    > Brian
    >
    >
    > On Mon, Mar 19, 2012 at 11:32 AM, Matt Neuburg <matt...> wrote:
    >
    >> On Fri, 16 Mar 2012 17:11:24 -0400, Marco Tabini <mtabini...> said:
    >>>> That time has passed now, so you can now completely specify IBOutlets
    >> (and IBActions) in your implementation file and hide the details from the
    >> outside world. If you want properties, you can use a class extension like
    >> so to add them:
    >>>
    >>> Sorry to hijack this conversation, but I've been meaning to ask: Where
    >> is this documented? I stumbled on this feature (and the ability to declare
    >> ivars directly in the .m file), but I didn't see it explained it anywhere.
    >> I'm sure I'm just not looking in the right place, but I can't find it
    >> anywhere.
    >>
    >> See Apple's document "The Objective-C Programming Language".
    >>
    >> In the chapter called "Defining a Class", not only is declaring an ivar
    >> in the .m file covered, but doing it in the .h file is downright
    >> discouraged (rightly so). In practice, this feature of Objective-C did not
    >> swim into most people's ken until Xcode 4.2, when LLVM because the default
    >> compiler.
    >>
    >> In the chapter called "Categories and Extensions", declaration of private
    >> properties is discussed. That feature is considerably older.
    >>
    >> m.
    >>
    >> PS And of course there's also my book, which makes much of these features.
    >>
    >> PPS The trouble with language improvements like this, and with documents
    >> like The Objective-C Programming Language, is that there's a terminus point
    >> somewhere and they don't tell you exactly when it is. What I mean is, you
    >> can surprise yourself by adopting an improvement of this sort and then
    >> opening your project in an earlier version of Xcode that doesn't understand
    >> it. Also, different *parts* of Xcode may not understand it; for example,
    >> your code will compile, but the feature where you can drag from an ivar to
    >> the nib editor to form an outlet might not work (though now, I believe, it
    >> does).
    >>
    >> --
    >> matt neuburg, phd = <matt...>, <http://www.apeth.net/matt/>
    >> A fool + a tool + an autorelease pool = cool!
    >> Programming iOS 5! http://shop.oreilly.com/product/0636920023562.do
    >>
    >
    >
  • On Mar 19, 2012, at 2:27 PM, Brian Lambert wrote:

    > Is there a way to declare ivars in the .M file AND have them accessible
    > from Objective-C Category files for the class?

    Use an extension instead of a category?

    Charles
  • On Mon, Mar 19, 2012 at 2:27 PM, Brian Lambert wrote:
    > Is there a way to declare ivars in the .M file AND have them accessible
    > from Objective-C Category files for the class?

    I will tell you how we handle public, private, and protected ivars and
    properties. The route we decided to take was influenced by a number of
    overall design goals:

    1) Embrace @properties. Properties are great. They make memory
    management easier, they work with ARC, and they force us to document
    our code and think about relationships between objects (weak vs
    strong, atomic vs nonatomic). Exposing _ivars in header files is
    gross. You never want people to access them directly, so don't make
    those declarations public at all. Exposing _ivars without properties
    in .m files is also gross, as it is not clear whether those
    relationships are supposed to be strong or weak.
    2) Technically, nothing is truly private in Objective-C, so let's stop
    trying to completely prevent people from using private APIs. Let's
    just adopt a convention that is clear and lets people know that if
    they use private APIs they do so at their own risk.
    3) Protected and private APIs (including ivars) should not
    autocomplete most of the time in Xcode, so they should not be in the
    public header file at all. We want the header file to be clear,
    concise, and very readable.

    Given those decisions, here is how we currently do things:

    * Public ivars are always declared as properties in the class header
    file. The _ivar should not be declared in the header file at all. Let
    the synthesizers declare them in the .m file. _ivars needlessly
    complicate the public header files for your classes, so keep them out.
    * Don't be afraid to mark many of your public properties as readonly.
    You can always override the property declaration as being readwrite in
    a class extension in the .m file.
    * Private ivars are declared as private @properties in the .m file.
    Again, let the synthesizers actually declare the _ivar. Don't declare
    the _ivars yourself, as it won't be immediately clear whether the
    references are supposed to be strong or weak. Use properties!
    * Protected methods and properties are tricky. We want subclasses to
    be able to access these directly, but we don't want API consumers to
    see them when autocompleting in Xcode or when looking at the public
    header file. So, we decided to do what Apple does with
    UIGestureRecognizerSubclass.h. We create a special header file that
    defines all of the protected properties and methods of a class using a
    category. Then, any subclass implementation files can import this file
    to easily access those protected APIs. Yes, nothing is stopping a bad
    developer from importing this header file and using protected APIs
    when they shouldn't, but they are hidden in a different file and
    appropriately documented so that developers don't accidentally use
    them.

    There are many ways to handle public, private, and protected APIs in
    Objective-C. We have found this to be a clean approach that works for
    us.

    - Sebastian
  • On Mar 19, 2012, at 12:27 PM, Brian Lambert <brianlambert...> wrote:
    > Regarding this:
    >
    > In the chapter called "Defining a Class", not only is declaring
    > an ivar in the .m file covered, but doing it in the .h file is downright
    > discouraged (rightly so). In practice, this feature of Objective-C...
    >
    > I can't stand thus sort of subtle crap.  If it's legal to declare ivars in
    > the .M file and the .H file, it's crap to say it's "discouraged" in the .H
    > file.  Either a language is well-designed, consistent, and carefully
    > thought out, or, it has turned into crap.

    No, it's a flexibility vs complexity tradeoff. We could change the language to make it impossible to declare ivars in a .h file, but then you lose the ability to write higher-performance struct-like classes. Similarly, we could make it impossible to declare ivars in a .m file, but then you lose the ability to write framework classes without exposing these implementation details. Both cases are useful. One of them happens to be better in most cases, so we "discourage" the other unless you really need it.

    > Is there a warning level for "You did something that's totally legal, but,
    > discouraged."?

    There are warnings of this form. For example, if you perform an assignment inside an `if` condition, the compiler will warn about it on the assumption that you probably meant to perform a comparison instead. The problem with this sort of warning is that there needs to be a clean way to say "no really, do the discouraged thing" to pacify the compiler.

    > I love Objective-C Category files because they
    > allow me to segment my implementation such that each file more or less
    > represents each interface that my class implements

    We like this too; it's commonly used inside system frameworks for large classes like NSWindow. In a recent version of Xcode we added optimizations to the linker so that there's no longer any extra runtime overhead if you write categories on your own classes in the same binary.

    > Is there a way to declare ivars in the .M file AND have them accessible
    > from Objective-C Category files for the class?

    You can keep ivars out of your public .h file and use them in categories. First, declare the ivars as @package in a class extension in another header file. Then #include that header file in your class implementation and your category implementations.

    // MyClass.h
    @interface MyClass : SomeSuperclass {
        // look ma, no ivars
    }
    @end

    // MyClass-Internal.h
    #import "MyClass.h"
    @interface MyClass () {  // class extension
      @package
        int anIvar;
    }
    @end

    // MyClass.m
    #import "MyClass-Internal.h"
    @implementation MyClass
    ...
    @end

    // MyClass-Category.m
    #import "MyClass-Internal.h"
    @implementation MyClass (Category)
    -(int)method { return anIvar; }
    @end

    --
    Greg Parker    <gparker...>    Runtime Wrangler
  • On Mar 19, 2012, at 12:45 PM, Brian Lambert wrote:

    > ivars in the .H file of my Foo class, which no one other than me will ever use, should be relatively OK.  After all, I'm not trying to prevent myself from knowing anything about my implementation of Foo.  I'm just trying to ensure that my *intent* for my class is well-understood to other programmers who will work on Foo in the future.

    In my experience, that's not a good way to think about what writing an OO program. (1) The main programmer who may work on Foo in the future may be me, but I think of him as one of those "other programmers". I can guarantee that I won't have the slightest idea what this program does or why my intent was, probably as soon as tomorrow, if I don't express it clearly in the program itself. (2) OOP is about expressing contracts. Now that ivars that are not intended as part of the public face of a class no longer have to be in the header file, it's best to take advantage of it if possible so that the program expresses the intended architecture.

    Here's a case where declaring the ivars in the implementation file wouldn't have worked for me:

    https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/ch37p
    920downloader/p754p772downloader/MyDownloaderPrivateProperties.h


    Okay, it's properties not ivars, but the idea is the same. I want a subclass of MyDownloader to know about these properties. The way to do that is to declare them in a class extension and have the subclass (MyImageDownloader) import the file with that class extension.

    Hope that helps -

    m.

    --
    matt neuburg, phd = <matt...>, http://www.apeth.net/matt/
    pantes anthropoi tou eidenai oregontai phusei
    Programming iOS 5! http://shop.oreilly.com/product/0636920023562.do
    RubyFrontier! http://www.apeth.com/RubyFrontierDocs/default.html
    TidBITS, Mac news and reviews since 1990, http://www.tidbits.com
  • On Mar 16, 2012, at 4:00 PM, Brian Lambert wrote:

    > I’ve been developing iOS applications full-time for about 6 months now and
    > I love it. I feel pretty strong on the platform now.
    >
    > I have a lingering question about something that’s really been bugging the
    > heck out of me, though, that I thought I would ask the list and get some
    > feedback on.
    >
    > It seems to be the case that when people are developing a UIViewController
    > subclass or a UIView subclass that they expose *all* the implementation
    > details of that class through public properties vs. using ivars.
    >
    > Here’s an example. For the purpose of this post, I’ve wrote a simple iPhone
    > app with one view. The link below is a screen shot of it:
    >
    > https://s3.amazonaws.com/Softwarenerd/MyApp.jpg
    >
    > For now, I used Interface Builder to generate the UI.  In doing so, I wound
    > up with:
    >
    > #import <UIKit/UIKit.h>
    >
    > // MyViewController interface.
    > @interface MyViewController : UIViewController
    >
    > // Properties.
    > @property (weak, nonatomic) IBOutlet UILabel * labelMyLabel;
    >
    > // buttonDoItTouchUpInside action.
    > - (IBAction)buttonDoItTouchUpInside:(id)sender;
    >
    > @end
    >
    > This means that my UILabel called labelMyLabel is publicly available.
    > Anyone who has access to an instance of MyViewController can do anything
    > they want to with my label, including replacing it.
    >
    > Also, anyone who has an instance of MyViewController can call my
    > buttonDoItTouchUpInside action.
    >
    > For example, in my AppDelegate, I can do:
    >
    > - (BOOL)application:(UIApplication *)application
    > didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    > {
    > self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen]
    > bounds]];
    >
    > MyViewController * myViewController = [[MyViewController alloc]
    > initWithNibName:@"MyViewController" bundle:nil];
    > [self setMyViewController:myViewController];
    > [[self window] setRootViewController:[self myViewController]];
    > [[self window] makeKeyAndVisible];
    >
    > // Mess with MyViewController!!!!  HAHAHAHA FU, MyViewController!!!!
    > [[myViewController labelMyLabel] setText:@"This is ridiculous!!!!"];
    > return YES;
    > }
    >
    > To me, this totally ridiculous. It breaks well-established rules of
    > encapsulation.
    >
      In part, I see your problem (the interface is just meant for IB, not for other programmers), but remember, the point of a controller object is to mediate between some view object (which may have subviews, etc...) and one or more model objects. The fact that the header declares your IBOutlets and IBActions is intentional, otherwise your design would be too-tightly coupled; this isn't good. Remember, MVC is a paradigm, not a hard-and-fast, set-in-stone set of laws. There are times when you should (and need to) break some of the design principles in order to uphold others; it all depends on what your design is attempting to do. Not only does IB need to know where the outlets and actions are, so do any other designers (including yourself at a later date) who then want to make an alternate view on your data; all they need to is connect the new view (xib) to your existing controller and wire up the outlets and actions. Sometimes we have to make trade-offs in order to get a design that works. In this case, the trade-off is exposing outlets and actions to possible code misuse, in order to be able to use a visual builder (IB) to make our user interfaces in a straight-forward manner.
      It's also part of what makes a dynamic language like ObjC so powerful; but - as always - with power comes responsibility. You could - if needed - substitute a UILabel subclass for the original, and your controller wouldn't know the difference, since - to it - what it has a reference to IS a UILabel, and acts like a UILabel, so it must be a UILabel! This is sometimes referred to as 'duck typing'; if it looks like a duck and acts like a duck, it's probably a duck; use it as such.
      HTH!
      Also, this post really belongs on the Cocoa list as this is a programming sort of problem, not a problem with Xcode usability.

    > From my analysis, it appears to be nothing more than an artifact of how
    > rehydrating NIBs works, and it totally compromises good OO software design
    > by leaking all the implementation details of MyViewController to the
    > outside world.
    >
    > Everyone, all the books, training materials, samples, and so on, just seem
    > to accept this style of doing things as being normal. In fact, one book I
    > read *encouraged* this technique of using public properties for ALL the
    > internal state of a class over using ivars. It said public properties were
    > preferable.
    >
      Here I agree with you; not everything should be public, just outlets and actions, or any model you need bindings too (or KVC/KVO compliance). Else, make it @private, or - better yet - make a named category at the top of your implementation file if you have any methods you don't want exposed to the outside world. Even if you put them in an @private section, it still announces, 'hey, there's some hidden stuff here!'.

    > What in the world is the deal with this??  :-)  Can anyone explain this do
    > me?
    >
    > Building this class without Interface builder, here’s how I coded it:
    >
    > // MyViewController implementation.
    > @implementation MyViewController
    > {
    > @private
    > UILabel * labelMyLabel_;
    > UIButton * buttonDoIt_;
    > }
    >
    > - (void)viewDidLoad
    > {
    > [super viewDidLoad];
    >
    > [[self view] setBackgroundColor:[UIColor whiteColor]];
    >
    > labelMyLabel_ = [[UILabel alloc] initWithFrame:CGRectMake(20.0, 20.0,
    > 280.0, 21.0)];
    > [labelMyLabel_ setText:@"I dare you to press Do It!"];
    > [[self view] addSubview:labelMyLabel_];
    >
    > buttonDoIt_ = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    > [buttonDoIt_ setFrame:CGRectMake(20.0, 49.0, 72.0, 37.0)];
    > [buttonDoIt_ setTitle:@"Do It" forState:UIControlStateNormal];
    > [buttonDoIt_ addTarget:self action:@selector(buttonDoItTouchUpInside:)
    > forControlEvents:UIControlEventTouchUpInside];
    > [[self view] addSubview:buttonDoIt_];
    > }
    >
    > - (void)viewDidUnload
    > {
    > [super viewDidUnload];
    > }
    >
    > // buttonDoItTouchUpInside action.
    > - (void)buttonDoItTouchUpInside:(id)sender
    > {
    > [labelMyLabel_ setText:@"You pressed Do It!"];
    > }
    >
    > @end
    >
    > To me, this is how things should be. The implementation details of how my
    > view works are hidden.
    >
    > Am I missing something?
    >
    > @property sure is convenient, but it seems to be misused a lot. A class
    > should expose properties that are public, and hide implementation details
    > that are not.
    >
    > Thanks!
    >
    > Brian
  • On Mar 19, 2012, at 7:28 PM, William Squires wrote:

    > The fact that the header declares your IBOutlets and IBActions is intentional, otherwise your design would be too-tightly coupled; this isn't good... Not only does IB need to know where the outlets and actions are, so do any other designers (including yourself at a later date) who then want to make an alternate view on your data; all they need to is connect the new view (xib) to your existing controller and wire up the outlets and actions.

    The thing about that is, in the latest versions of Xcode, IB *doesn’t* need IBOutlets and IBActions to be in the header. You can put this stuff in the .m file, and IB finds it just fine.

    Charles
  • You can use the class extensions in your implementation files for outlets to keep them private. You can also just drag your actions directly into your implementation file and leave them out of your header file. This will keep them private as well.

    In general you should try to keep your header file as clean as possible. Use class extensions for properties that need to remain private and just wire actions directly to your implementation file.

    -Tony

    Sent from my iPad

    On Mar 19, 2012, at 8:28 PM, William Squires <wsquires...> wrote:

    >
    > On Mar 16, 2012, at 4:00 PM, Brian Lambert wrote:
    >
    >> I’ve been developing iOS applications full-time for about 6 months now and
    >> I love it. I feel pretty strong on the platform now.
    >>
    >> I have a lingering question about something that’s really been bugging the
    >> heck out of me, though, that I thought I would ask the list and get some
    >> feedback on.
    >>
    >> It seems to be the case that when people are developing a UIViewController
    >> subclass or a UIView subclass that they expose *all* the implementation
    >> details of that class through public properties vs. using ivars.
    >>
    >> Here’s an example. For the purpose of this post, I’ve wrote a simple iPhone
    >> app with one view. The link below is a screen shot of it:
    >>
    >> https://s3.amazonaws.com/Softwarenerd/MyApp.jpg
    >>
    >> For now, I used Interface Builder to generate the UI.  In doing so, I wound
    >> up with:
    >>
    >> #import <UIKit/UIKit.h>
    >>
    >> // MyViewController interface.
    >> @interface MyViewController : UIViewController
    >>
    >> // Properties.
    >> @property (weak, nonatomic) IBOutlet UILabel * labelMyLabel;
    >>
    >> // buttonDoItTouchUpInside action.
    >> - (IBAction)buttonDoItTouchUpInside:(id)sender;
    >>
    >> @end
    >>
    >> This means that my UILabel called labelMyLabel is publicly available.
    >> Anyone who has access to an instance of MyViewController can do anything
    >> they want to with my label, including replacing it.
    >>
    >> Also, anyone who has an instance of MyViewController can call my
    >> buttonDoItTouchUpInside action.
    >>
    >> For example, in my AppDelegate, I can do:
    >>
    >> - (BOOL)application:(UIApplication *)application
    >> didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    >> {
    >> self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen]
    >> bounds]];
    >>
    >> MyViewController * myViewController = [[MyViewController alloc]
    >> initWithNibName:@"MyViewController" bundle:nil];
    >> [self setMyViewController:myViewController];
    >> [[self window] setRootViewController:[self myViewController]];
    >> [[self window] makeKeyAndVisible];
    >>
    >> // Mess with MyViewController!!!!  HAHAHAHA FU, MyViewController!!!!
    >> [[myViewController labelMyLabel] setText:@"This is ridiculous!!!!"];
    >> return YES;
    >> }
    >>
    >> To me, this totally ridiculous. It breaks well-established rules of
    >> encapsulation.
    >>
    > In part, I see your problem (the interface is just meant for IB, not for other programmers), but remember, the point of a controller object is to mediate between some view object (which may have subviews, etc...) and one or more model objects. The fact that the header declares your IBOutlets and IBActions is intentional, otherwise your design would be too-tightly coupled; this isn't good. Remember, MVC is a paradigm, not a hard-and-fast, set-in-stone set of laws. There are times when you should (and need to) break some of the design principles in order to uphold others; it all depends on what your design is attempting to do. Not only does IB need to know where the outlets and actions are, so do any other designers (including yourself at a later date) who then want to make an alternate view on your data; all they need to is connect the new view (xib) to your existing controller and wire up the outlets and actions. Sometimes we have to make trade-offs in order to get a design that works. In this case, the trade-off is exposing outlets and actions to possible code misuse, in order to be able to use a visual builder (IB) to make our user interfaces in a straight-forward manner.
    > It's also part of what makes a dynamic language like ObjC so powerful; but - as always - with power comes responsibility. You could - if needed - substitute a UILabel subclass for the original, and your controller wouldn't know the difference, since - to it - what it has a reference to IS a UILabel, and acts like a UILabel, so it must be a UILabel! This is sometimes referred to as 'duck typing'; if it looks like a duck and acts like a duck, it's probably a duck; use it as such.
    > HTH!
    > Also, this post really belongs on the Cocoa list as this is a programming sort of problem, not a problem with Xcode usability.
    >
    >> From my analysis, it appears to be nothing more than an artifact of how
    >> rehydrating NIBs works, and it totally compromises good OO software design
    >> by leaking all the implementation details of MyViewController to the
    >> outside world.
    >>
    >> Everyone, all the books, training materials, samples, and so on, just seem
    >> to accept this style of doing things as being normal. In fact, one book I
    >> read *encouraged* this technique of using public properties for ALL the
    >> internal state of a class over using ivars. It said public properties were
    >> preferable.
    >>
    > Here I agree with you; not everything should be public, just outlets and actions, or any model you need bindings too (or KVC/KVO compliance). Else, make it @private, or - better yet - make a named category at the top of your implementation file if you have any methods you don't want exposed to the outside world. Even if you put them in an @private section, it still announces, 'hey, there's some hidden stuff here!'.
    >
    >> What in the world is the deal with this??  :-)  Can anyone explain this do
    >> me?
    >>
    >> Building this class without Interface builder, here’s how I coded it:
    >>
    >> // MyViewController implementation.
    >> @implementation MyViewController
    >> {
    >> @private
    >> UILabel * labelMyLabel_;
    >> UIButton * buttonDoIt_;
    >> }
    >>
    >> - (void)viewDidLoad
    >> {
    >> [super viewDidLoad];
    >>
    >> [[self view] setBackgroundColor:[UIColor whiteColor]];
    >>
    >> labelMyLabel_ = [[UILabel alloc] initWithFrame:CGRectMake(20.0, 20.0,
    >> 280.0, 21.0)];
    >> [labelMyLabel_ setText:@"I dare you to press Do It!"];
    >> [[self view] addSubview:labelMyLabel_];
    >>
    >> buttonDoIt_ = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    >> [buttonDoIt_ setFrame:CGRectMake(20.0, 49.0, 72.0, 37.0)];
    >> [buttonDoIt_ setTitle:@"Do It" forState:UIControlStateNormal];
    >> [buttonDoIt_ addTarget:self action:@selector(buttonDoItTouchUpInside:)
    >> forControlEvents:UIControlEventTouchUpInside];
    >> [[self view] addSubview:buttonDoIt_];
    >> }
    >>
    >> - (void)viewDidUnload
    >> {
    >> [super viewDidUnload];
    >> }
    >>
    >> // buttonDoItTouchUpInside action.
    >> - (void)buttonDoItTouchUpInside:(id)sender
    >> {
    >> [labelMyLabel_ setText:@"You pressed Do It!"];
    >> }
    >>
    >> @end
    >>
    >> To me, this is how things should be. The implementation details of how my
    >> view works are hidden.
    >>
    >> Am I missing something?
    >>
    >> @property sure is convenient, but it seems to be misused a lot. A class
    >> should expose properties that are public, and hide implementation details
    >> that are not.
    >>
    >> Thanks!
    >>
    >> Brian
    >
    >
    > _______________________________________________
    > Do not post admin requests to the list. They will be ignored.
    > Xcode-users mailing list      (<Xcode-users...>)
    > Help/Unsubscribe/Update your Subscription:
    > https://lists.apple.com/mailman/options/xcode-users/<azatelli...>
    >
    > This email sent to <azatelli...>
  • > It seems to be the case that when people are developing a UIViewController subclass or a UIView subclass that they expose *all* the implementation details of that class through public properties vs. using ivars.

    There's no need to use @property. Just manually declare your IBOutlets as @private variables:

    @interface MyViewController : UIViewController
    {
    @private
      IBOutlet UILabel * label;
    }

    Only add accessors (manually or with @property) for those ivars you want to be public. If you want to use accessors within your controller then add accessor methods to the implementation file without declaring them in the header file.

    Simon
  • On Mon, Mar 19, 2012 at 1:35 PM, Sebastian Celis
    <lists...>wrote:

    > 1) Embrace @properties...Exposing _ivars in header files is
    > gross. You never want people to access them directly, so don't make
    > those declarations public at all.
    >

    > 2) Technically, nothing is truly private in Objective-C, so let's stop
    > trying to completely prevent people from using private APIs.

    contradiction++
  • >
    >
    >> 2) Technically, nothing is truly private in Objective-C, so let's stop
    >> trying to completely prevent people from using private APIs.
    >
    >
    > contradiction++
    > _______________________________________________
    >
    >
    Not quite. You actually CAN hide the ivars and it is odd to expose them
    because you have the ability to hide them. Exposing the accessor method
    INSTEAD of the ivar is usually better. I know that it is not always
    convenient and hope that we eventually get the ability to access self's
    ivars if we are in the same compilation unit, but until then, exposing
    accessors seems like a better option.

    TJ
  • Well damn, @package accomplishes the 'compilation unit' request.
    On Thu, Mar 22, 2012 at 8:36 PM, T.J. Usiyan <griotspeak...> wrote:

    >
    >>> 2) Technically, nothing is truly private in Objective-C, so let's stop
    >>> trying to completely prevent people from using private APIs.
    >>
    >>
    >> contradiction++
    >> _______________________________________________
    >>
    >>
    > Not quite. You actually CAN hide the ivars and it is odd to expose them
    > because you have the ability to hide them. Exposing the accessor method
    > INSTEAD of the ivar is usually better. I know that it is not always
    > convenient and hope that we eventually get the ability to access self's
    > ivars if we are in the same compilation unit, but until then, exposing
    > accessors seems like a better option.
    >
    > TJ
    >
  • On Thu, Mar 22, 2012 at 6:39 PM, G S <stokestack...> wrote:
    > On Mon, Mar 19, 2012 at 1:35 PM, Sebastian Celis
    > <lists...>wrote:
    >
    >> 1) Embrace @properties...Exposing _ivars in header files is
    >> gross. You never want people to access them directly, so don't make
    >> those declarations public at all.
    >>
    >
    >> 2) Technically, nothing is truly private in Objective-C, so let's stop
    >> trying to completely prevent people from using private APIs.
    >
    > contradiction++

    I think you misunderstood.

    My point on (1) was that directly referencing ivars of other classes
    with the -> operator is generally frowned upon in Objective-C. For
    one, you miss out on KVO that way. It is generally much more accepted
    to use real Objective-C methods and properties. Because of this,
    putting ivars in a *public* header file is strange and just clutters
    up what could otherwise be a clean, compact public interface
    declaration.

    My point on (2) was to just try and steer the conversation away from
    where it had been headed, which was an expansive discussion on how
    Objective-C handles public / protected / private methods and
    properties. Yes, private methods aren't really private. I can always
    use NSInvocation to call your private methods if I really want to.
    What I think is much more interesting is finding the best way to
    create compact, readable public header files that API consumers can
    reference while still finding good ways to use both traditionally
    private and protected methods in your class and subclasses. I just
    want to keep those out of the public header file — not to *prevent*
    you from using them, but just to communicate to you that you should
    try to avoid them.

    - Sebastian
previous month march 2012 next month
MTWTFSS
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  
Go to today