Search code examples
objective-cprivate-membersclass-members

Objective-C : How may I hide a class member from outside the class?


I'm fighting with something and I don't find any satisfying solution.

I have a class with a "myMutableArray" member.

I would like the class to manage itself adding and removing items from the array, so I don't want any other class being able to access the member and call NSMutableArray methods on it.

In an ideal situation, I would like to have a private getter (to be able to call self.myMutableArray) and a public setter for this member.

Do you know how I may achieve this ?

In other words :

I would like other classes

be able to call

- [oneInstance setMyMutableArray:thisArray]; // set
- oneInstance.myMutableArray = thisArray; // set using setter

- thisArray = oneInstance.myMutableArray; // get
- [oneInstance addItem:anItem]; // add

not being able to call :

- [oneInstance.myMutableArray add:etc...] // add

I would like my class

be able to call

- self.myMytableArray = [NSMutableArray array]; // set
- thisArray = self.myMytableArray ; // get

Thank you.


Solution

  • Foo.h

    @interface Foo : NSObject
    @property(readonly, retain) NSArray * myReadonlyArray;
    - (void) addItem: (Item *) anItem;
    - (BOOL) publiclyDoSomething;
    @end
    

    Foo.m

    @interface Foo()
    @property(readwrite, retain) NSMutableArray * myMutableArray;
    - (void) doSomethingInPrivate;
    @end
    
    @implementation Foo
    @synthesize myMutableArray = myMutableArray_;
    
    - (void) addItem: (Item *) anItem
    {
        // assuming myMutableArray_ was already iniitialized
        [self.myMutableArray addObject: anItem];
    }
    
    - (NSArray *)myReadonlyArray
    {
         return self.myMutableArray;
    }
    
    ... rest of methods (including the public/private) implementations ...
    @end
    

    Some details:

    • Objective-C has "instance variables", not "member variables".

    • The above defines a public getter and private setter that is synthesized automatically. For clarity's sake, I also added a public method and a private method.

    • "Public" and "private" in Objective-C are defined entirely by visibility to the compiler. The setter for myMutableArray and the method doSomethingInPrivate are only private because their declarations in an @interface cannot be imported.

    • self.myMutableArray and [self myMutableArray] do the same thing; the . syntax is merely short hand for an equivalent method call (with a few edge case details beyond this question)

    • @property in the @interface is purely short hand for method declarations (with a bit of extra metadata).

    • @interface Foo() is a class extension and not a category. It exists for exactly the purpose demonstrated above; to extend the @interface of a class with additional declarative information whose scope should be limited. It can appear in a header file that, say, you only import in your library's implementation to create library-private functionality.

    • @dynamic is used when you neither @synthesize an @property nor provide a conventional method implementation. It is not needed otherwise!

    I'm probably forgetting something.