Category usage in Objective-C - objective-c

I'm seeing some code I've inherited that looks like the following:
#interface SomeClass (private)
This is within SomeClass.m, the implementation file. There is an accompanying header file which doesn't suggest that the class is using a category. Is (private) in this case just a poor name given to a category for SomeClass? And I'm assuming it's perfectly legitimate to specify categories such as these in an implementation?

It isn't the name "private" that makes it private; the methods are private because they are in a category declared within the implementation file.
There are three uses of a category, each of which add methods to a class (note: methods only, not iVars)
Extending an existing Cocoa class
This lets you add your own methods to an existing class.
For example, if you want to extend NSString to apply special capitalization, you could create a new class called, say NSString+Capitals. in the NSString+Capitals.h you would have:
#interface NSString (Capitals)
-(NSString *)alternateCaps:(NSString *)aString;
#end
and in NSString+Capitals.m you would implement the method
#implementation NSString (Capitals)
-(NSString *)alternateCaps:(NSString *)aString
{
// Implementation
}
Private methods on a class
This is the same as above, except that the extra methods are declared and defined in the implementation file (.m) Usually a way of having private methods - because they are not in the .h file (which is the one #imported by other classes) they are simply not visible. In this case, the implementation of the methods are done in their own implementation block. e.g
// someClass.m
#interface someClass (extension)
-(void)extend;
#end
#implementation someClass
// all the methods declared in the .h file and any superclass
// overrides in this block
#end
#implementation someClass (extension)
-(void)extend {
// implement private method here;
}
Class Extension (New for 10.5 Leopard)
A simpler way of having private methods. In this special case, the category name is empty and the private methods are implemented in the same block as all the other class methods.
// someClass.m
#interface someClass ()
-(void)extend;
#end
#implementation someClass
// all the methods declared in the .h file and any superclass
// overrides in this block
// Implement private methods in this block as well.
-(void)extend {
// implement private method here;
}
#end
Here's a link to the Apple docs on Categories and extensions.

"Private" is just a name that suggests the methods are not public and are used for the internal implementation of the class, but there's nothing in the declaration of the category that enforces that.
Also, methods defined in a category are added to the class definition at runtime, so the accompanying header file need not declare that it is using a category -- it gets "used" automatically.

I use that to give me somewhere to declare (and thus document, as well as shut the compiler up about) helper methods which don't need to be in the public interface. Then the "consumers" of the class are (tacitly, given that there's nothing stopping them other than good manners) restricted to using methods defined in the header file.

Related

Instance variables in extension vs implementation

In Objective-C, for instance variables that one doesn't want to put in the header file and, one can put them either in the class extension:
#interface MyClass () {
NSString *myInstanceVariable;
}
// ...
#end
or in the class implementation:
#implementation MyClass {
NSString *myInstanceVariable;
}
// ...
#end
Is there any difference between them?
In the first example you posted, myInstanceVariable is declared in the interface but not explicitly declared as private so it's protected, not private. Protected is the default.
In the second example you posted, myInstanceVariable is declared in the implementation rather than the interface and so it is private.
My preference would be to list it as #private in the interface.

Objective C Private Public Methods In Same Category

What I'd like to do is separate a category's methods into private and public methods. The private methods need to be visible outside of that category's file, but not outside the class.
For instance, let's say I have the following files:
ClassA.m
ClassA.h // <-- Includes definitions of public category methods
ClassAPrivates.h // <-- Includes definition of private category methods.
ClassA+Render.m
ClassAPrivates.h would look like this:
#interface ClassA()
// private methods here, for use inside ClassA
#end
#interface ClassA(Render)
// the private methods of the Render category.
-(void)privateConfigureDeviceContext;
-(void)privateConfigureBufferSpace;
#end
And 'ClassA.h' would look like this:
#interface ClassA : NSObject
// public methods of ClassA
#end
#interface ClassA (Render)
// public methods of category Render
-(void)drawLine;
-(void)drawCircle;
#end
However, XCode complains about duplicate interface for Render. Any workarounds?
No need to create separate categories for private methods.
There are 3 scenarios:
ClassA+Render.m accessing the private methods that are defined in the ClassA.m
ClassA.m accessing the private methods that are defined in ClassA+Render.m
ClassA+Render.m accessing the properties defined in ClassA.m
Note: Though the original poster hasn't asked for Scenario 3, I thought it might come in handy
Example
ClassA.m defines 2 private methods
basePrivateMethod1 - This would invoke renderPrivateMethod1
basePrivateMethod2
ClassA+Render.m defines 2 private methods
renderPrivateMethod1
renderPrivateMethod2 - This would invoke basePrivateMethod2
Scenario 1
In ClassA+Render.m just create an extension and forward declare the methods that you want to use.
ClassA+Render.m
#interface ClassA ()
- (void) basePrivateMethod1; //Just forward declare the method
#end
Scenario 2
In ClassA+Render.h just declare the methods defined in ClassA+Render.m.
In ClassA.m just include (#import) ClassA+Render.h
Pls note, ClassA+Render.h would / should not be used outside of ClassA
ClassA+Render.h
#interface ClassA (Render)
{
- (void) basePrivateMethod2;
}
Scenario 3
Pls note - Properties can not be defined / created in the categories
So create a new category called ClassA+Properties
In ClassA+Properties.h redeclare all the properties
In ClassA+Properties.m use #dynamic for all the properties to tell the compiler that the actual definition of these properties is else where
In ClassA+Render.m include (#import) ClassA+Properties.h, so that all the properties are accessible
ClassA+Properties.h
#interface ClassA (Properties)
{
#property NSUInteger property1;
#property NSUInteger property2;
}
ClassA+Properties.m
#interface ClassA (Properties)
{
#dynamic property1;
#dynamic property2;
}
You declare two categories named Render on ClassA. That is why Xcode is complaining.
Category is a concept which states any new method can be added to an existing class and all subclass will eventually get that method.
You use categories to define additional methods of an existing class—even one whose source code is unavailable to you—without subclassing. You typically use a category to add methods to an existing class, such as one defined in the Cocoa frameworks. The added methods are inherited by subclasses and are indistinguishable at runtime from the original methods of the class.
If you are adding private method, then why to go with category? As it can be used only by that single class file itself. Therefore why not to create a normal private method!!!
You can declare Render's private methods in a class extension in its own file. This takes advantage that you can have multiple class extensions.
ClassA.h:
#interface ClassA : NSObject
// public methods of ClassA
#end
ClassA+Render.h:
#interface ClassA (Render)
// public methods of category Render
-(void)drawLine;
-(void)drawCircle;
#end
ClassA+Render_Private.h:
#interface ClassA ()
// the private methods of the Render category.
-(void)privateConfigureDeviceContext;
-(void)privateConfigureBufferSpace;
#end

Declaring method prototypes in header and implementation

I am learning object orientated programming from the online Stanford courses there is a part I am unsure of regarding declarations. I thought that you must always declare the prototype in the header and then write the code in the implementation file, but the professor wrote a method in the implementation without a declaration prototype in the header file, how come?
Also, may someone please clear the difference between private and public and if the method without a prototype is public or private? The method without a prototype is not from a super class.
That is a perfectly legal way to declare methods that are not to be used outside the class implementation itself.
The compiler will find methods in the implementation file as long as they precede the method in which they are used. However that will not always be the case, as the new LLVM compiler allows methods to be declared in any order and referenced from a given file.
There are a couple of different styles for declaring methods inside an implementation file:
//In the Header File, MyClass.h
#interface MyClass : NSObject
#end
//in the implementation file, MyClass.m
//Method Decls inside a Private Category
#interface MyClass (_Private)
- (void)doSomething;
#end
//As a class extension (new to LLVM compiler)
#interface MyClass ()
- (void)doSomething;
#end
#implementation MyClass
//You can also simply implement a method with no formal "forward" declaration
//in this case you must declare the method before you use it, unless you're using the
//latest LLVM Compiler (See the WWDC Session on Modern Objective C)
- (void)doSomething {
}
- (void)foo {
[self doSomething];
}
#end
If you write the method in you header file it is public and accessible for other classes / objects. If you do not declare it in the header file the method is a private method meaning that you can access it internally in you class but no other class can use this method.

Questions regarding Objective-C private method example

The following is an example of how to create 'private' methods in Objective-C:
MyClass.m
#import "MyClass.h"
#import <stdio.h>
#implementation MyClass
-(void) publicMethod {
printf( "public method\n" );
}
#end
// private methods
#interface MyClass (Private)
-(void) privateMethod;
#end
#implementation MyClass (Private)
-(void) privateMethod {
printf( "private method\n" );
}
#end
Why does this example use the (Private) category name in the #interface MyClass (Private) and #implementation MyClass (Private) declarations? Aren't interfaces declared in .m files automatically private? Do we need 2 different implementation blocks?
Is there a variation of this technique to create 'protected' methods?
(I'm new to objective-C. Am I missing the point of category names? Why do we need to use them in this instance?)
Thanks-
If you're creating a category, you have to give it some name. The name Private for the category doesn't have any special meaning to the language.
Also, in modern Objective-C, this would be a better case for a class extension, which is declared like a nameless category (#interface MyClass ()) but the implementation goes in the main #implementation block. This is a relatively recent addition, though. The secret-category method in your example is the more traditional way of accomplishing roughly the same thing.
The (Private) part declares a category for MyClass. The category name can be anything, but all categories interpreted by the compiler will add the methods from that category to the list of known methods for that class as a whole. By putting the private methods in a category at the top of a source file, you can declare the public interface to your class in your main .h file but all of your private methods will be “hidden” inside the .m file, all the while you are still able to use those methods without the compiler warning that the methods weren't found.
The category name is only to “categorise” the methods of a class. You can categorise them any way you want. The name is not important, simply calling the category Private does not make those methods private, they are still able to be overridden by subclasses and able to be discovered by introspection.
Basically, you are just separating the public interface from your class from your private interface. If you have to ship a library with its headers, the headers will not contain any of the private methods.
Typically though, the private interface is placed at the top of the source file so that the compiler interprets it (and finds all the methods that the category provides) before interpreting your main and private implementations.

Is it possible to declare a method as private in Objective-C?

Is it possible to declare a method as private in Objective-C?
If you're working in Objective-C 2.0, the best way to create methods that are "hard" for others to call is to put them in a class extension. Assuming you have
#interface MyClass : NSObject {
}
- (id)aPublicMethod;
#end
in a MyClass.h file, you can add to your MyClass.m the following:
#interface MyClass () //note the empty category name
- (id)aPrivateMethod;
#end
#implementation MyClass
- (id)aPublicMethod {...}
- (id)aPrivateMethod {...} //extension method implemented in class implementation block
#end
The advanage of a class extension is that the "extension" methods are implemented in the original class body. Thus, you don't have to worry about which #implementation block a method implementation is in and the compiler will give a warning if the extension method is not implemented in the class' #implementation.
As others have pointed out, the Objective-C runtime will not enforce the privateness of your methods (and its not too hard to find out what those methods are using class dump, even without the source code), but the compiler will generate a warning if someone tries to call them. In general, the ObjC community takes a "I told you not to call this method [by putting it in a private class extension or category or just by documenting that the method is private] and you called it anyways. Whatever mess ensues is your fault. Don't be stupid." attitude to this issue.
No, any object can send any message to any other object. You can, however, put the method in a category that's part of the class's implementation file. That way, you'll get a "Class may not implement this method" warning if you try to call it anywhere else. That's the normal way of making a method "private."
There is nothing that will prevent the method being called (since objective-c is message based anything can be sent any message), but you can declare them outside of the header so they are not visible and the compiler will generate warnings if used.
This works for both class and instance methods.
E.g.
#import "SomeClass.h"
// Interface for hidden methods
#interface SomeClass (hidden)
+(void) hiddenClassMethod;
-(void) hiddenInstanceMethod;
#end
Note: Do NOT declare variables like this or they will become class-variables - e.g. only one variable will be used by all instances.
You can do so by using categories. I've got a fuller description in my answer to this SO question.
As has been said, you can't stop anyone sending a message to a selector, but by using categories you can reduce the visibility of these functions.
Also, you can have more than one category extending a class. So, by using informative category names you can group private functions into related blocks, improving the self-documenting nature of your code.
As others mentioned, you can't have code that's
a method, and
impossible to call from outside a class.
Folks have already pointed out that you can abandon point 2, and get a method that's hard-but-not-impossible to call. Alternatively, why not abandon point 1?
static id myPrivateMethod(MyObject *me, int arg1, id arg2) { ... }
Now the code can only be called from within same file. You don't get any of the magic private-member access you can get with a method, so this is by no means a perfect solution. But there's no better way to achieve privacy.
To implement hidden methods (instance and/or class)
// ===========================
// = File: SomeClass.m
// ===========================
#import "SomeClass.h"
// =================================
// = Interface for hidden methods
// =================================
#interface SomeClass (hidden)
-(void) hiddenInstanceMethod;
#end
// ================================
// = Implementation for SomeClass
// ================================
#implementation SomeClass
-(void) hiddenInstanceMethod
{
printf( "Hidden instance method\n" );
}
-(void) msg
{
printf("Inside msg()...\n");
[self hiddenInstanceMethod];//private method calling
}
#end
http://macdevelopertips.com/objective-c/private-methods.html
reffer this link it will be helpful .