0

I'm a fan of not exposing class variables unless needed. In most objective-c code I see, the variables are declared as properties even if they are never to be used by an outsider.

@interface DetailViewController : UIViewController {
    __weak IBOutlet UILabel *name;
}

vs

@interface DetailViewController : UIViewController

@property (weak, nonatomic) UILabel *name;

As a student of Software Engineering, this seams to me to be a pretty bad violation of principles such as encapsulation and could potentially lead to unwanted coupling in a large project.

I do understand the KVC aspects of using properties, but not why one would expose variables which are clearly only meant to be used internally in the class, such as the UILabel above.

Could someone explain why this is the preferred way when working with Objective-C on iOS?

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Pétur Ingi Egilsson
  • 4,368
  • 5
  • 44
  • 72
  • 3
    This has *not* been the preferred way for a while. You are now encouraged to hide them inside and @implementation MyClass { int myIvar ;}, and finally these are _instance_ variables, not _class_ variables. – verec Oct 18 '13 at 20:51
  • or you can create category in implementation file to extend your interface and define remaining private property – bhawesh Oct 18 '13 at 20:54
  • @HotLicks Your comment is not helpful at all. Full of FUD and bashing? Flagged. – Pétur Ingi Egilsson Oct 18 '13 at 23:19
  • @Pétur - What FUD, what bashing? I'm just telling it like it is. (And add to that that Xcode is a (rapidly) moving target. It's hard enough to keep up with the critical stuff like ARC, so there's not much time to learn -- and put into practice -- the new ways you can define fields and properties *this* week.) – Hot Licks Oct 19 '13 at 01:25

3 Answers3

4

Properties encapsulate the memory management (eg assign, retain, copy, strong, weak) of a iVar, while direct access to an iVar (instance variable) does not. This greatly reduces memory bugs.

Non-public properties can be declared at the top of the .m so there's no reason for them to be in the header:

@interface DetailViewController ()
@property (weak, nonatomic) NSString *name;
@end

Properties do create ivars that can be accessed. For the example above, with an explicitly synthesized property, the ivar would be named name while an implicitly synthesized synthesized property will have a leading underscore _name.

IBOutlets are declared in the header even though other classes don't need access to them as they are required so that Interface Builder connect to them and the nib loading system can populate the outlets. IBOutlets are most often going to be views, such as your UILabel.

Edit:

The previous paragraph about IBOulets is a legacy method required for Xcode 3 and earlier. However, newer versions of Xcode can use outlets defined in the implementation file just as the property above thanks to tighter integration of the InterfaceBuilder to the rest of the IDE.

BergQuester
  • 6,167
  • 27
  • 39
  • 4
    Interestingly, `IBOutlets` are no longer required in the header. I don't know when that happened, but lately I've been putting them in the class extension in the .m file and it works fine. – Brian Oct 18 '13 at 20:59
  • Interesting, I'll have to check that out. Might have something to do with the greater integration of XC and IB since version 4. If that's the case, I'll gladly clean up my headers and edit my answer! – BergQuester Oct 18 '13 at 21:01
  • It's true. Many of my View Controllers now generally have no public methods, ivars, properties, nothing declared in the header. It's very nice. – Rob Napier Oct 18 '13 at 21:49
  • Sweet, looks like it is supported: https://developer.apple.com/library/mac/documentation/ToolsLanguages/Conceptual/Xcode_Overview/Edit_User_Interfaces/edit_user_interface.html#//apple_ref/doc/uid/TP40010215-CH6-SW1 – BergQuester Oct 18 '13 at 21:59
1

What you see is an old style. Earlier Objective-C compilers required that you declare instance variables in the interface. However, by default they are @protected, so not everyone can just use them.

Current best practice is that you don't declare instance variables at all but use properties, unless you need to declare them (if you have a custom getter for a readonly property, or both custom getter and setter for a readwrite property, no instance variable is generated automatically), that you declare them in your .m file unless someone really needs to access them, that you declare properties and methods in your .m file unless someone needs to access them, and that you don't declare methods at all unless needed.

It's also quite common to declare a property as readonly in the header file, and redeclare it as read/write in the implementation.

In other words, hide what you can hide.

gnasher729
  • 51,477
  • 5
  • 75
  • 98
0

The first example indicates that you want to use the label as an outlet for a Xib or Storyboard. This answer sheds some light on that case: https://stackoverflow.com/a/1236985/171933

In general, however, you don't need to declare internal instance variables as properties. Actually, you can move them completely out of the header by putting them into your .m file like so:

@implementation DetailViewController 
{
    NSInteger _someValue;
    UILabel *_someLabel;
}

That way you can really only keep the things in the header that should be visible to the outside. And those things would typically either be properties or plain old methods.

Community
  • 1
  • 1
Johannes Fahrenkrug
  • 42,912
  • 19
  • 126
  • 165