9

I've started learning Objective-C a few weeks ago and I still don't understand how to manage the encapsulation of a class correctly. What is the best way to declare a private member variable in a class?

It seems that setting the right getter/setter for your member variable with "@property" is the right way to go, more than just declaring it "@private" in the interface. But it seems to me that this still gives other classes an access to these variables. Even if you declare the property "readonly", an outside class can access the reference to the member variable and modify it!

So I'm guessing the best way to declare a private member variable is to not include any guetter/setter by not declaring a property. Am i right? Or is there a better way?

Thanks

apaderno
  • 28,547
  • 16
  • 75
  • 90
Michael Eilers Smith
  • 8,466
  • 20
  • 71
  • 106

1 Answers1

23

if you don't want it accessible to other classes, declare the @property on your implementation, creating an anonymous category for your class.

Header file:

// MyClass.h
@interface MyClass : NSObject {
    NSObject *_privateObject;
    NSObject *_readonlyObject;
    NSObject *_publicObject;
}

@property (nonatomic, retain, readonly) NSObject *readonlyObject;
@property (nonatomic, retain) NSObject *publicObject;

@end

Implementation:

// MyClass.m
@interface MyClass ()
    @property (nonatomic, retain) NSObject *privateObject;
    // Make it writable on the implementation
    @property (nonatomic, retain, readwrite) NSObject *readonlyObject;
@end

@implementation MyClass

@synthesize privateObject = _privateObject;
@synthesize readonlyObject = _readonlyObject;
@synthesize publicObject = _publicObject;

These are examples of three different properties.

  • privateObject is not visible on other classes;
  • readonlyObject is visible but is read only;
  • publicObject is visible and can be get and set;
vfn
  • 6,026
  • 2
  • 34
  • 45
  • Ok, so using a category I can totally hide a member variable. But I still don't get the point of using "readonly" for a visible member, since it returns the reference to the object. One can just modify the reference and write over it, even if it has no setter. – Michael Eilers Smith Aug 26 '10 at 02:41
  • Good point! I'll try to investigate what kind of protection objective-c give to it. My guess is that as soon as you attempt to change the value of your referenced object it make a copy and the changes don't propagate to the protected object. Here it is the documentation: http://developer.apple.com/mac/library/documentation/cocoa/conceptual/objectivec/Articles/ocProperties.html#//apple_ref/doc/uid/TP30001163-CH17-SW19 – vfn Aug 26 '10 at 03:14
  • @Oliver, would you mind to create another question for that, and put your code there to give to us a better understanding of this issue. BTW "unrecognized selector" means that you don't have that specific selector, that can be a property or a method. Are you sure you've declared the property with "readwrite" privileges? – vfn Sep 18 '11 at 23:34
  • Hi @Oliver, I think your are a little bit confused. My answer works with any Objective-C/C/C++ type or Objective-C objects. The crash that you are get is probably dua to a lack of understanding on how the selectors/messaging system works on Objective-C. Without looking to your code, it would be really complicated to guess what you are doing wrong. – vfn Sep 19 '11 at 06:47
  • @Oliver, what about your property and synthesize? How did you write them them? I don't know how much you know about Obj-C properties or class inheritance, but NSMutableArray is a subclass of NSArray, that's a subclass of NSObject. As I've said previously the "unrecognized selector" when calling "setMyMutableArray" means that you are not implementing the "setMyMutableArray" method. Please, create a new question with your code for the .h and .m files. This is the way this site works. Comments shouldn't be used to questions/answers, and unfortunately there is nothing wrong on my answer. – vfn Sep 19 '11 at 23:47
  • @vfn : rollback for my comments. I've tested it again and again, and I still don't know why, but I did not reproduce the problem I was talking about. But... Using a NSMutableThing, I found that the property readOnly does not prevent adding an object into it. Could you enhance your answer to add the way of doing a really readOnly property ? I guess the right way is to write the accessor manually to return a non mutable object. But I can't achieve creating the accessor method because it generates duplicates with the prop. Perhaps you have a better solution that may maintain the retain property. – Oliver Sep 20 '11 at 07:36
  • @Oliver, If you want to prevent a mutable object of being mutated, the problem is completelly different from a private/non-writable property. If you really need to protect your mutable iVar, you can declare your property as non-mutable. Let's say `NSMutableArray *_myArray;` and property `@property(nonatomic, retain, readonly) NSArray *myArray;` and on your anonymous category, you write `@property (nonatomic, retain, readwrite) NSMutableArray *myArray;` – vfn Sep 20 '11 at 23:12
  • @vfn : Yes, of course, that's what I thought to do. But doing that way, that raises a permanent warning on the anonymous category, some useful warnings on the `addObject` calls, and most of all, that doesn't prevent the array to be modified. I wondered if you had another way of doing but to write oneself both setter and getter to manage that. But here, I agree with you, it's another question that coud be asked. – Oliver Sep 20 '11 at 23:58