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
> _______________________________________________
> 
> Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)
> 
> Please do not post admin requests or moderator comments to the list.
> Contact the moderators at cocoa-dev-admins(at)lists.apple.com
> 
> Help/Unsubscribe/Update your Subscription:
> https://lists.apple.com/mailman/options/cocoa-dev/wsquires%40satx.rr.com
> 
> This email sent to wsqui...@satx.rr.com


_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to