I'm working on a static library for iOS and want to implement some methods that are public for use by the other classes in the library but not outwardly visible. Basically, I want to create something similar to Apple's "private" API calls.
I'm ok with someone being able to call these methods given that they discover their name, but I just want to mask them from the header file that's packaged with the library so that XCode doesn't give them the option to call those methods by default, possibly throwing a warning.
Any idea how this can be accomplished?
One idea is the following -
You can define the "private" methods of your class in a separate category in a separate .h file. For example, you could have class A looking like the following:
A.h
#interface A : NSObject {
}
- (void) foo; //public method
#end
Now the private methods of A can be declared in a different file:
A+Internal.h
#interface A (Internal)
- (void) bar; //private method
#end
The implementation file of A (A.m) can have implementations for both sets of methods.
In your static library, you do not publish the header files with "+Internal" in the name. Users of your library will only see methods in A.h, but classes inside your library can use both.
You can declare your "private" methods in a category #interface MyClass(PrivateMethods)or a class extension #interface MyClass() at the top of the .m file or in its own private header file.
From Extensions:
Class extensions are like anonymous categories, except that the methods they declare must be implemented in the main #implementation block for the corresponding class.
It is common for a class to have a publicly declared API and to then have additional methods declared privately for use solely by the class or the framework within which the class resides. You can declare such methods in a category (or in more than one category) in a private header file or implementation file as mentioned above. This works, but the compiler cannot verify that all declared methods are implemented.
Class extensions allow you to declare additional required methods for a class in locations other than within the primary class #interface block.
See also:
Best way to define private methods for a class in Objective-C
Related
Im looking at some source code written by someone else and its intrigues me to see this line:
#interface UITableView (MyTableViewGestureDelegate)
Now I have previously seen only this:
#interface MyTableView : UITableView <MyTableViewGestureDelegate>
so I am a lil confused.
Any ideas as what to what im looking at?
Ben
It is class category declaration - using categories you can split your class implementation into several files or add methods to existing classes.
It is a category declaration.
A category allows you to add methods to an existing class—even to one
for which you do not have the source. Categories are a powerful
feature that allows you to extend the functionality of existing
classes without subclassing. Using categories, you can also distribute
the implementation of your own classes among several files. Class
extensions are similar, but allow additional required APIs to be
declared for a class in locations other than within the primary class
#interface block.
The declaration of a category interface looks very much like a class interface declaration—except the category name is listed within parentheses after the class name and the superclass isn’t mentioned. Unless its methods don’t access any instance variables of the class, the category must import the interface file for the class it extends:
General Syntax:
#import "ClassName.h"
#interface ClassName ( CategoryName )
// method declarations
#end
Note that a category can’t declare additional instance variables for the class; it includes only methods. However, all instance variables within the scope of the class are also within the scope of the category. That includes all instance variables declared by the class, even ones declared #private.
There’s no limit to the number of categories that you can add to a class, but each category name must be different, and each should declare and define a different set of methods.
Please check the link and Example
MyTableView : UITableView < MyTableViewGestureDelegate > says your class MyTableView - subclass of UITableView - implements the protocol named MyTableViewGestureDelegate
UITableView (MyTableViewGestureDelegate) says you are creating a Category for the Class UITableView named MyTableViewGestureDelegate
I want to prepare small static library for below classes in objective-c :
Class A, Class B, Class C. I want to include these classes in static library. Now Class A can access public members of methods of Class B or Class C.
Now When I integrate above library in other project,
I prepare Class D which can access only Class A and Class B
Not Class C. How can I do this ?
My other doubt is assume that
NSString *isValid is declared in Class B.
I want that above variable can be accessed from Class A and Class C
I mean included files of library can access above variable.
But from outside library above variable can't be accessed.
How can make it private so that it can be accessed within the library itself and not outside the library ?
Thanks for help !
You can make public methods only visible to your static library but invisible out side of it.
Here is how to do it.
1) Create a header file to be used outside of your library
#import <Foundation/Foundation.h>
#interface ClassA : NSObject
#property(nonatomic,readwrite)BOOL publicProperty;
-(void)publicMethod;
#end
2) Create a category to be only used internally by the static library
#import "ClassA.h"
#interface ClassA (Internal)
#property(nonatomic,readwrite)BOOL privateProperty;
-(void)privateMethod;
#end
Note Name this file: "ClassA+Internal.h"
3) Declare your private properties and methods again in the .m file
#import "ClassA.h"
#interface ClassA ()
#property(nonatomic,readwrite)BOOL privateProperty;
-(void)privateMethod;
#end
#implementation ClassA
#synthesize publicProperty;
#synthesize privateProperty;
//...
#end
Using private properties and methods inside the static library
In your ClassB.m file import header file of the ClassA category
#import "ClassB.h"
#import "ClassA.h"
#import "ClassA+Internal.h"
Now you have access to the private properties and methods of ClassA
Creating static library without private properties and methods
When you create you static library keep the "ClassA+Internal.h" category header file inside "private" or "project" headers section of "Build Phases","Copy Headers"
This way when you build your static library the ClassA+Internal.h category will be inaccessible to the outside.
As far as I know, there is no way in Obj-C to protect access to public members like you need it. A common approach is simply not to include the methods and ivars in the header file that you are shipping with the static library. For compiling the library yourself, you must of course use your complete private header.
Note that this does not work for Objective-C++ where the class structure must be known to the client of the library at compile time.
Suppose I want to have a private method of a class to be visible to the implementation of that class only so that the class' interface exposes only what needs to be exposed. In some recent versions of Xcode, I can do this simply by omitting the method's declaration in the header. However, one good book suggests that I should also declare a category in the implementation file and declare that method within it, like this:
// [in MyClass.m]
#import "MyClass.h"
// category declaration - is it really required?
// edit: it's a class extension declaration, I know, but it doesn't change much
#interface MyClass ()
- (void)myPrivateMethod;
#end
#implementation MyClass
- (void)myPrivateMethod
{
// do something
}
// all methods here can call myPrivateMethod
#end
Indeed it does compile and work. Moreover, it does compile and work fine without the category/extension declaration part. This rises a natural question:
If I have a bunch of private methods, do I need to declare all of them in a category? What would be the best practice?
This is not a category, it's a class extension (note that there is no category name, the parentheses are empty).
It is a very good idea to add your private methods to a class extension. Doing so ensures that all methods have declarations, and that these declarations are visible only to the parts of your code where you want them to be visible.
Note that unlike ordinary categories, class extensions let you add instance variables. This is very convenient when your implementation relies on classes that are not part of the interface of your class.
I'm aware that Objective-C doesn't support real private methods. What I'm currently doing to declare 'private' methods is adding the following to class .m files:
#interface MyClass()
- (void) privateMethodName;
#end
The Problem:
If I now add a subclass, and want to use this 'private' method, I can't! I get the error:
Receiver type 'SubClassName' for instance message does not declare a
method with selector 'privateMethodName'
So, if I don't want non-subclasses to be able to access this method, but do want subclasses to be able to, what can I do? What is the best/proper way of achieving my goal?
You could separate the "protected" interface from the public one. In the primary header, just declare the public methods:
MyMagicThingy.h:
#interface MyMagicThingy: NSObject
- (void) publicMethod;
#end
Then, have an additional header with protected methods:
MyMagicThingy+Protected.h:
#import "MyMagicThingy.h"
#interface MyMagicThingy (Protected)
- (void) protectedMethods;
#end
You cannot have "real" private/protected/public methods in Objective C (as in: the compiler will enforce access rules. All methods are public). You have to go with a convention.
What you describe is really a protected method. One approach to overcome this: Ivars can be declared #public, #protected, or #private. You could declare a protected helper instance to restrict access to derived instances, which then calls back through the object which holds it.
Another alternative in some cases would be to make the subclasses write to an interface, then keep your implementation private.
Sometimes, you just have to document "don't do this, unless you are not a subclass" because it's not part of the language. In this mindset, a separate header which declares a category of protected methods is one of my favorite. It's pretty well hidden from clients, but can be made visible to subclasses by explicit inclusion -- Dirk provided an example of this at the same time, check it out.
Lastly, if you're comfortable with ObjC++, C++ offers this control, so you can mix modes and visibility quite freely.
First and foremost
You can't get anyone to not being able to call any method that is implemented on an object in Objective-C (at least not without burning through several dozen razors making Yaks less weatherproof).
Just don't call methods that are not declared in public header files, as a convention (this is, what you're already doing).
Second
The word public in the above paragraph does the trick:
In Objective-C (at least in its current incarnation), a class's interface can be defined over any number of header files using the technique you just described in your post: Class continuations.
One such example of an Apple framework class doing that would be UIGestureRecognizer with its separate subclassing header UIGestureRecognizerSubclass.h.
PS:
The error you are seeing reeks of using ARC so your runtime is definitely recent enough to even use multiple implementation files for that.
Like:
#interface ClassXXName(private)
- (void) xxxfunctions
#end
or user category methods?
#interface Foo() creates a class extension (I stand corrected, props to bbum) on interface Foo which is like additional methods added to the interface. Some people also use #interafce Foo(Private) (category) instead of a class extension with (). It's more like "injecting" new methods into a class from outside the class.
Placing this in the .m file just keeps other things from "seeing it" in the .h file, but that's it. Basically people normally use categories or class extensions in .m files to specify private interfaces, but they are also used for things like UIKit uses categories to add row and section public methods to NSIndexPath. (This can be confusing.)
You don't really need to define private methods this way, but if you have a method called bar that calls method foo before foo is defined in the source file you'll get a compiler warning something like "object self may not respond to foo". You can get rid of that by defining foo before you define bar or any other foo-calling code. It's the same with plain C and functions.
Like Ole says this doesn't stop anyone from calling the private methods, it just declares your intention that they be private and causes the compiler to generate the "may not respond to" warnings even if they import the .h file.