16

I am wring a class that has a bunch of properties that I want to only use internally. Meaning I don't want to be able to have a user access them when they have created my class. Here is what I have in my .h but it still doesn't hide those from the autocomplete menu (hitting escape to see list) in XCode:

@interface Lines : UIView {
    UIColor *lineColor;
    CGFloat lineWidth;

    @private
        NSMutableArray *data;
        NSMutableArray *computedData;
        CGRect originalFrame;
        UIBezierPath *linePath;
        float point;
        float xCount;
}


@property (nonatomic, retain) UIColor *lineColor;
@property (nonatomic) CGFloat lineWidth;
@property (nonatomic) CGRect originalFrame;
@property (nonatomic, retain) UIBezierPath *linePath;
@property (nonatomic) float point;
@property (nonatomic) float xCount;
@property (nonatomic, retain) NSMutableArray *data;
@property (nonatomic, retain) NSMutableArray *computedData;

I thought that using @private was what I needed, but maybe I have done it wrong. Does something need to also be done in my .m?

Nic Hubbard
  • 41,587
  • 63
  • 251
  • 412

1 Answers1

38

@private only affects ivars. It doesn't affect properties. If you want to avoid making properties public, put them in a class extension instead. In your .m file, at the top, put something like

@interface Lines ()
@property (nonatomic) CGRect originalFrame;
// etc.
@end

This looks like a category, except the category "name" is blank. It's called a class extension, and the compiler treats it as if it were part of the original @interface block. But since it's in the .m file, it's only visible to code in that .m file, and code outside it can only see the public properties that are declared in the header.

Lily Ballard
  • 182,031
  • 33
  • 381
  • 347
  • Ok, I saw someone elsewhere talk about that. So do I not even put anything about originalFrame in my .h? Only in my .m? – Nic Hubbard Oct 26 '11 at 22:11
  • 1
    Defeinitely the correct answer, but I think the accessors will still show up in the completion list (in that same file). – Richard Oct 26 '11 at 22:13
  • 1
    @NicHubbard: Correct. In the modern runtime (64bit desktop, or any iOS) you don't even need to declare your ivars, the properties will synthesize backing ivars if explicitly-declared ones don't exist. If you still need to support 32bit desktop then you do need to declare your ivars, but you can leave those behind the `@private` wall. – Lily Ballard Oct 26 '11 at 22:15
  • @Richard: They'll show up in code sense *in the .m file*. Everywhere else they won't, since code sense only shows what's visible to the compiler at that precise location. – Lily Ballard Oct 26 '11 at 22:15
  • 1
    @NicHubbard: Well then, I may as well continue :) If you're on the modern runtime, and you still need an explicit ivar (there are still some circumstances where ivars are preferable to properties), you can declare it inside the @implementation block instead of the @interface to avoid polluting your header with private implementation details. Just use `@implementation { /* ivars here */ } /* methods here */ @end`. – Lily Ballard Oct 26 '11 at 22:21
  • @KevinBallard Thanks, this will be good to know for the future. – Nic Hubbard Oct 26 '11 at 22:25
  • @Kevin yes, that's what I said too! – Richard Oct 28 '11 at 16:23
  • What about if I wanna subclass the class and access the property (that is private in the superclass)? – Van Du Tran Nov 21 '12 at 20:29
  • @VanDuTran: Create a "private" header, such as `MyClass_Private.h`, and put your class extension there. Import this in your .m file and in any subclass. If you're building a library/framework, this header should be marked either Private or Project (depending on your needs). – Lily Ballard Nov 22 '12 at 08:59
  • Well explained, another slight objective-c mystery unravelled. – JamesB Sep 30 '13 at 13:00