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

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.

Is there any reason you need the public setter? It sounds like the class itself owns the array. You'd probably be better off not providing any public property access to the field, and making a public method which copies the values into your private field.
// public interface, in the .h file
#interface MyClass : // superclass, protocols, etc.
- (void) setSomething:(NSArray *)values;
#end
// private interface, not in the .h
#interface MyClass ()
#property (/* attributes */) NSMutableArray *myMutableArray;
#end
#implementation MyClass
#synthesize myMutableArray = myMutableArray_;
- (void) setSomething:(NSArray *)values
{
[self.myMutableArray setArray:values];
}
#end

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.

Related

Best way to define private variables in Objective-C

I want to define private instance variables in MyClass.m file. It seems to me there are two ways to do it:
use class extension
#interface HelloViewController ()
{
int value;
}
define in #implementation section
#implementation HelloViewController
{
int value;
}
Which is better?
I think recent Apple's coding style is to use class extension?
e.g. MasterViewController.m generated by 'Master-Detail Application Template'
#interface MasterViewController () {
NSMutableArray *_objects;
}
#end
The "Modern Objective-C" way to do this is to declare them in your implementation block, like this:
#implementation ClassName {
int privateInteger;
MyObject *privateObject;
}
// method implementations etc...
#end
See this earlier post of me with more details.
#interface HelloViewController ()
{
#private //optional, this is old style
int vale;
}
If you were making a library, though, theoretically no one would know about any methods you didn't declare in the header files.
Copied from: How to make a real private instance variable?
Declaring instance variables in the #implementation is a recent
feature of Obj-C, this is why you see a lot of code with them in the
#interface - there was no other choice.
If you are using a compiler which supports declaring instance
variables in the implementation declaring them there is probably the
best default - only put them in the interface if they need to be
accessed by others.
Instance variables declared in the implementation are implicitly
hidden (effectively private) and the visibility cannot be changed -
#public, #protected and #private do not produce compiler errors (with
the current Clang at least) but are ignored.
Copied from: Private ivar in #interface or #implementation
In my view the best is to define it like private properties that you can access as fields or properties just within your implementation, the advatage is that you can access them by self as well as by _fieldName syntax what is handy in some situations.
#interface SignUpController ()
#property ViewHeaderView*header; //private properties/fields
#property UITextField*activeField;
#property CGFloat keyboardHeight;
#end
#implementation SignUpController {
}
#end

Using ObjC class extensions' vars in class category

I declare a class extension interface adding vars to it. Is it possible to access those vars in a category of that class?
Sure - any variable is accessible through the runtime, even if it isn't visible in the #interface:
SomeClass.h
#interface SomeClass : NSObject {
int integerIvar;
}
// methods
#end
SomeClass.m
#interface SomeClass() {
id idVar;
}
#end
#implementation SomeClass
// methods
#end
SomeClass+Category.m
#implementation SomeClass(Category)
-(void) doSomething {
// notice that we use KVC here, instead of trying to get the ivar ourselves.
// This has the advantage of auto-boxing the result, at the cost of some performance.
// If you'd like to be able to use regex for the query, you should check out this answer:
// http://stackoverflow.com/a/12047015/427309
static NSString *varName = #"idVar"; // change this to the name of the variable you need
id theIvar = [self valueForKey:varName];
// if you want to set the ivar, then do this:
[self setValue:theIvar forKey:varName];
}
#end
You can also use KVC to get iVars of classes in UIKit or similar, while being easier to use than pure runtime-hacking.

Add ivars in #implementation

For good encapsulation, decent Objective-C programmers put their private ivars in a private extension declared in the main implementation file, like this:
// MyClass.m
#interface MyClass () {
float value;
}
#end
#implementation MyClass
#end
But recently, I found a simpler way to hide private ivars: ivars can be declared in a {} block following #implementation, like this:
// MyClass.m
#implementation MyClass {
float value;
}
#end
It is really handy when no private methods but only private ivars need to be hidden.
However, I'm not sure about its syntax validity. Can anyone validate or invalidate it with some canonical references?
It's perfectly valid and here is a document by Apple talking about it:
https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/EncapsulatingData/EncapsulatingData.html#//apple_ref/doc/uid/TP40011210-CH5-SW6
I don't personally use it as I prefer the syntax of a class continuation category.
I was also curious about this. Here is the updated link from Apple:
You Can Define Instance Variables without Properties
It’s best practice to use a property on an object any time you need to keep track of a value or another object.
If you do need to define your own instance variables without declaring a property, you can add them inside braces at the top of the class interface or implementation, like this:
#interface SomeClass : NSObject {
NSString *_myNonPropertyInstanceVariable;
}
...
#end
#implementation SomeClass {
NSString *_anotherCustomInstanceVariable;
}
...
#end

Protected methods in Objective-C

What is the equivalent to protected methods in Objective-C?
I want to define methods which only the derived classes may call/implement.
You can simulate protected and private access to methods by doing the following:
Declare your private methods in a class extension (i.e. a unnamed category declared near the top of the class' .m file)
Declare your protected methods in a Subclass header – Apple uses this pattern with respect to UIGestureRecognizer (see documentation and reference to UIGestureRecognizerSubclass.h)
These protections are not, as Sachin noted, enforced at runtime (as they are in Java, for example).
You can neither declare a method protected or private. Objective-C's dynamic nature makes it impossible to implement access controls for methods. (You could do it by heavily
modifying the compiler or runtime, at a severe speed penalty, but for obvious reasons this is not done.)
Taken from Source.
Here is what I did to get protected methods visible to my subclasses, without requiring them to implement the methods themselves. This meant I didn't get compiler warnings in my subclass about having an incomplete implementation.
SuperClassProtectedMethods.h (protocol file):
#protocol SuperClassProtectedMethods <NSObject>
- (void) protectMethod:(NSObject *)foo;
#end
#interface SuperClass (ProtectedMethods) < SuperClassProtectedMethods >
#end
SuperClass.m: (compiler will now force you to add protected methods)
#import "SuperClassProtectedMethods.h"
#implementation SuperClass
- (void) protectedMethod:(NSObject *)foo {}
#end
SubClass.m:
#import "SuperClassProtectedMethods.h"
// Subclass can now call the protected methods, but no external classes importing .h files will be able to see the protected methods.
I just discovered this and it works for me.To improve upon Adam's answer, in your superclass make an implementation of the protected method in .m file but don't declare it in .h file. In your subclass make a new category in your .m file with the declaration of the protected method of the superclass and you can use the protected method of the superclass in your subclass. This will not ultimately prevent the caller of the supposedly protected method if forced at runtime.
/////// SuperClass.h
#interface SuperClass
#end
/////// SuperClass.m
#implementation SuperClass
- (void) protectedMethod
{}
#end
/////// SubClass.h
#interface SubClass : SuperClass
#end
/////// SubClass.m
#interface SubClass (Protected)
- (void) protectedMethod ;
#end
#implementation SubClass
- (void) callerOfProtectedMethod
{
[self protectedMethod] ; // this will not generate warning
}
#end
Another way using #protected variables.
#interface SuperClass:NSObject{
#protected
SEL protectedMehodSelector;
}
- (void) hackIt;
#end
#implementation SuperClass
-(id)init{
self = [super init];
if(self) {
protectedMethodSelector = #selector(baseHandling);
}
return self;
}
- (void) baseHandling {
// execute your code here
}
-(void) hackIt {
[self performSelector: protectedMethodSelector];
}
#end
#interface SubClass:SuperClass
#end
#implementation SubClass
-(id)init{
self = [super init];
if(self) {
protectedMethodSelector = #selector(customHandling);
}
return self;
}
- (void) customHandling {
// execute your custom code here
}
#end
You can define the method as a private method of the parent class and can use [super performSelector:#selector(privateMethod)]; in the child class.
You can sort of do this with a category.
#interface SomeClass (Protected)
-(void)doMadProtectedThings;
#end
#implementation SomeClass (Protected)
- (void)doMadProtectedThings{
NSLog(#"As long as the .h isn't imported into a class of completely different family, these methods will never be seen. You have to import this header into the subclasses of the super instance though.");
}
#end
The methods aren't hidden if you import the category in another class, but you just don't. Due to the dynamic nature of Objective-C it's actually impossible to completely hide a method regardless of a calling instance type.
The best way to go is probably the class continuation category as answered by #Brian Westphal but you'll have to redefine the method in this category for each subclassed instance.
One option is to use class extension to hide methods.
In .h:
#interface SomeAppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#end
In .m:
#interface SomeAppDelegate()
- (void)localMethod;
#end
#implementation SomeAppDelegate
- (void)localMethod
{
}
#end
I usually name protected method with internal prefix:
-(void) internalMethod;

how to make a single method in a class to private in Objective-c?

how to make a single method in a class to private in Objective-c?
There's no concept of private methods in Objective-C. What you can do, however, is obmitting the method in the header file and adding a category in a private file.
Usually this is down like this:
#interface MyObject : NSObject {
// ivars
}
// public methods
#end
// usually in a seperate file
#interface MyObject ()
// private methods
#end
An empty name for a category means that it's a class extension, this tells the compiler that the method is required in the main implementation block.
You can't strictly speaking create private methods in Objective-C; but you can create a category in the file containg the implementation (MyClass.m), hiding it from the header file (MyClass.h).
//MyClass.h
#import <Foundation/Foundation.h>
#interface MyClass : NSObject {
}
#end
Implementation file:
//MyClass.m
#interface MyClass ()
- (void)myPrivateMethod;
#end
#implementation MyClass
- (void)myPrivateMethod {
return;
}
#end
Objective-C doesn't support private methods natively by design.
However, you can achieve private method control by using "class extensions" (anonymous categories).
The basic idea is to declare a class extension with your private methods inside the implementation file for your class (not its header), but outside of your #implementation block. You can then implement the methods and no outside class will be able to see them. Like this:
#interface MyClass ()
- (void)myPrivateMethod;
#end
#implementation MyClass
- (void)myPrivateMethod
{
//implementation goes here
}
-(void)someOtherMethod
{
[self myPrivateMethod];
}
#end
Using a class extension forces you to implement the methods in the main #implementation block and requires that they are implemented (much like as if they were declared in the main #interface block in the header).
Unfortunately, due to Objective-C's dynamic nature, this won't actually prevent those methods from being called by other classes. They will get a warning telling them that the class may not respond to the message, but at runtime it will work. The only thing this gives you is the ability to hide the methods from other programmers.
You can't. Only instance variables can be marked as private.
Though there are ways to do something equivalent to private methods.
The general idea is that you don't declare the private method in your header but in your implementation file.
Therefore, if you'd want to have a public (myPublicMethod) and private (myPrivateMethod) method, you're header could look like this:
#interface MyClass {
}
- (void)myPublicMethod;
#end
And then you have three options for your implementation file:
1.
Don't declare the method in any #interface section and just make sure it's implemented before it's being used in the #implementation section.
#implementation MyClass
- (void)myPrivateMethod { }
- (void)myPublicMethod {
[self myPrivateMethod];
}
#end
2.
Use an anonymous category in your implementation file to declare the private methods and implement them in the main #implementation block.
#interface MyClass ()
- (void)myPrivateMethod;
#end
#implementation MyClass
- (void)myPrivateMethod { }
- (void)myPublicMethod {
[self myPrivateMethod];
}
#end
3.
Use a regular category in your implementation file and implement the private methods in a separate #implementation block.
#interface MyClass (PrivateMethods)
- (void)myPrivateMethod;
#end
#implementation MyClass (PrivateMethods)
- (void)myPrivateMethod { }
#end
#implementation MyClass
- (void)myPublicMethod {
[self myPrivateMethod];
}
#end