Hide properties from the public

I am trying to declare properties that are intended for internal use only in the Private category as such:

 @interface BarLayer (Private) @property (readwrite, retain) MenuItemFont *menuButton; @property (readwrite, retain) Menu *menuMenu; @property (readwrite, retain) LabelAtlas *messageLabel; @end 

Now I'm trying to figure out exactly where I should @synthesize .

I tried:

 @implementation BarLayer (Private) @synthesize menuButton = _menuButton; @synthesize menuMenu = _menuMenu; @synthesize messageLabel = _messageLabel; @end 

Here the compiler complains:

@synthesize is not allowed in the category implementation

So I tried to put it in my BarLayer implementation, but here it does not find the declaration in the BarLayer interface.

no property declaration for 'menuButton found in interface

What will be the correct way?

+24
objective-c
Apr 13 '09 at 10:47
source share
6 answers

Actually, with the latest LLVM compiler, this problem can be solved much better. The previously recommended method to hide as much as possible about your properties was to declare your variables in your .h, prefix them with _, declare the property in the class extension in the private .m and @synthesize this property in your @ implementation.

With the latest LLVM (3.0), you can go even further by hiding everything about your property, including ivar support. Its declaration can be moved to .m and even omitted there, in which case it will be synthesized by the compiler (thanks to Ivan):

Car.h:

 @interface Car : NSObject - (void)drive; @end 

Car.m:

 @interface Car () @property (assign) BOOL driving; @end @implementation Car @synthesize driving; - (void)drive { self.driving = YES; } @end 
+1
Oct 21 2018-11-11T00:
source share
โ€” -

You cannot use @synthesize with a category.

You can do this with a class extension (anonymous aka category), which is just a category without a name, whose methods should be implemented in the main @implementation block for this class. For your code, just change "(private)" to "()" and use @synthesize in the main @implementation block along with the rest of your code for this class.

See Apple docs on extensions for more on this. (Apparently this is new on Mac OS 10.5.)

EDIT: Example:

 // Main interface (in .h) @interface Foo : NSObject - (void)bar; @end // Private interface (in .m, or private .h) @interface Foo () @property (nonatomic, copy) NSString *myData; @end @implementation Foo @synthesize myData; // only needed for Xcode 4.3 and earlier - (void)bar { ... } @end 

Another solution that works a lot more is to use objc_setAssociatedObject and objc_getAssociatedObject to fake additional instance variables. In this case, you can declare them as properties and implement setters and getters yourself using the objc_ * execution methods described above. For more information on these features, see Apple docs at Objective-C runtime .

+42
Apr 13 '09 at 11:42
source share

I found an explanation why property synthesis is not allowed in categories, but how you can use class extensions :

The following information comes from http://www.friday.com/bbum/2009/09/11/class-extensions-explained/

"Synthesis of the reason was prohibited in categories because synthesis required storage, and it was not possible to effectively declare storage in a category, and was deemed acceptable to allow categories to synthesize methods that could then directly influence ivars classes. Fragile and ugly.

However, it was also obvious that it would be possible to declare a property that was open for reading only, but whose implementation was read for intra-class or framework purposes.

Another requirement is that the synthesis of such properties should always be able to synthesize both the setter and getter naturally and accurately. In particular, when declaring a property as atomic, the developer cannot correctly manually write only 1/2 pairs of getter installers; the locking infrastructure does not open and, therefore, there is no way to guarantee atomicity in such a situation.

Class extensions fixed this problem elegantly.

In particular, you can declare a property like:

 @interface MyClass : NSObject @property(readonly) NSView *targetView; @end 

And then in the implementation file:

 @interface MyClass() @property(readwrite) NSView *targetView; @end @implementation MyClass @synthesize targetView; @end 

Final result? A property that is publicly read only, but privately read without revealing properties, up to the entire fragility of pleasure associated with categories.

+12
Jul 15 '10 at 0:30
source share

Scott Stevenson ( http://theocacao.com/ ) explains in his blog post, "Fast Objective-C 2.0 Tutorial: Part II," how to get Public properties with private setters . Following his advice, you will get a read-only property that has a private setter that can be used with point syntax. Hope this helps ...

+8
Apr 13 '09 at 11:53
source share

I just want to add my 2 cents and make it clear to people that it is possible to add properties to an existing class through categories (not class extensions). This requires the use of associative links, but it really is not so bad.

I wrote a post about this here if someone wants more information.

There is another question that touches on this topic, but it is rather meager in detail .

Greetings

+2
Nov 02 '11 at 20:45
source share

Since categories can only add methods to a class, you cannot get around this by trying to define property methods in a category.

You can declare properties derived from existing classes. For example. If your class has a property firstName and lastName , you can declare a property named fullName in the @implementation category.

 @interface Bar (Private) @property (readonly) NSString *fullName; // Note readonly, you have nothing to write to. @end 

However, you cannot simply @synthesize this property, you will have to write your own accessory, because the compiler has no idea where you want this value from.

 @implementation Bar (Private) - (NSString *)fullName { NSString *returnString = [NSString stringWithFormat:@"%@ %@", self.firstName, self.lastName]; } 

From the point of view of class design, Iโ€™m not sure that the idea of โ€‹โ€‹private property makes sense: I personally think of properties as what the class publicly reveals.

you can use the @private keyword in the BarLayer class to at least add some protection to its state.

+1
Apr 13 '09 at 11:41
source share



All Articles