0

I think I've been using Objective-C properties incorrectly. Specifically, I've been treating them like instance variables.

Here's an example of a recent interface:

// AIClass.h

#import "AIDataUtils.h"

@interface AIViewController : UIViewController

@property (strong, nonatomic) AIDataUtils *dataUtils;

@end

Then, in my implementation, I would use self.dataUtils as a way for any method in the class to easily access the same thing. No object from the outside would ever be interacting with that property.

What I'm realizing is that what I should have been doing is importing and declaring AIDataUtils in the implementation and not the interface. I think that would look like this:

// AIClass.m

#import "AIDataUtils.h"

@interface AIViewController ()
{
    AIDataUtils *dataUtils;
}
@end

@implementation AIViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    dataUtils = [[AIDataUtils alloc] init];
    ...
}

The docs say:

Avoid explicitly declaring public instance variables. Developers should concern themselves with an object’s interface, not with the details of how it stores its data.

My understanding here is if another object has no business touching AIDataUtils, don't put it in the interface. The fact that a property exists in an interface should be a hint that you're supposed to feed or do something with that property.

Am I hot or cold?

jmoneystl
  • 773
  • 1
  • 8
  • 23

2 Answers2

2

My understanding here is if another object has no business touching AIDataUtils, don't put it in the interface.

You're right, but that doesn't mean that you can't keep using properties for internal values too -- just don't declare them in your public interface. Usually, using a class extension as you've suggested is a fine way to have your properties while still keeping internal things (more or less) private.

There was a period in the evolution of Objective-C when properties were very helpful in managing memory -- if you used a property's accessors everywhere, you could worry a lot less about when to retain and when to release something because the accessors would do that for you. Now that we have ARC, the memory management aspect of properties is less important, but a lot of us are still conditioned to use properties even for internal stuff. If nothing else, internal-only properties can make your code a little more consistent-looking.

Caleb
  • 124,013
  • 19
  • 183
  • 272
1

If you intend dataUtils to be a private implementation detail, then you shouldn't declare it in the @interface in the header file.

Even if you want to keep it private, you can still make it a property in the .m file:

@interface AIViewController ()

@property (strong, nonatomic) AIDataUtils *dataUtils;

@end

Whether to make it a property or just an instance variable is a matter of taste and depends on how you use it. For example, if you only want to allocate the AIDataUtils instance lazily, you might as well make it a property and do the lazy allocation in the getter.

If you decide to make it an instance variable, there's probably no reason to declare it in a class extension. You can just declare it in the @implementation:

@implementation AIViewController {
    AIDataUtils *dataUtils;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    dataUtils = [[AIDataUtils alloc] init];
    ...

You can learn more about where to declare instance variables in this answer.

Community
  • 1
  • 1
rob mayoff
  • 375,296
  • 67
  • 796
  • 848