Are methods declared in categories visible to other classes - objective-c

Suppose I have the following
FileName : DBManager.h
#import <Foundation/Foundation.h>
#interface DBManager : NSObject
//Notice no method is declared here
#end
Now its implementation file looks like this
FileName: DBManager.m
#import "DBManager.h"
#interface DBManager()
+ (DBManager*) SomeMethod;
#end
#implementation DBManager
+ (DBManager*) SomeMethod
{
....
return SomePtr;
}
#end
Now in some other class method if I do the following
[DBManager SomeMethod] ; //Error No known class method for selector 'SomeMethod'
However if SomeMethod is declared inside the .h file inside of category then this works fine. I wanted to know if this was a limitation of categories that the methods are not visible to other classes ?

First, #interface DBManager() is not a category, it's a class extension. There's no identifier between the parentheses.
Second, the issue isn't visibility based on whether the method is declared in a class, category, or class extension, it's whether it was declared in the same translation unit.
A translation unit is a source file after the preprocessor has included/imported the header files (or whatever other files have been included/imported).
The error is telling you that the declaration of +SomeMethod was not declared in the translation unit. If it were, there'd be no error, regardless of whether it were declared in the class interface, a category, or a class extension.
It follows that if you declare the interface of a category in a header file and include the header file in a source file, you can use the methods declared by that category in that source file.

Related

#interface and #implementation in same file (no header file, Xcode unit test template)

Xcode generates this template code for a new Objective-C test case. Why does it not generate a header file and puts the #interface in the implementation file?
#import <XCTest/XCTest.h>
#interface BYObjCTest : XCTestCase
#end
#implementation BYObjCTest
// test methods
#end
How is this construct called? Is this a private class? Test cases are generally not needed to be called from outside of user code, is this the reason this is generated this way?
It's ok to have the interface ClassName : Superclass block (called the class declaration block) in a .m file.
Declaring a class in a Header (.h) file is more common because it's for class that needs be public (class that will be used in other class), but if your class is not meant to be used in outside of the .m file, then it's ok to have the declaration and implementation in the same .m or .mm file.
In the test of TestClass for example, they are not used anywhere else,so no need for a header.
Other language would call those private class. Well private class in objC have no .h file :)

Varieties of #interface declarations, some with parentheses

I've noticed a variety of #interface declarations for Objective-c classes. I'd like to understand why developers declare #interface in the following ways:
// in the .h file
#interface MyClass : NSObject
// ...
#end
// in the .m file (what's the purpose of the parens?)
#interface MyClass ()
// more property declarations which seem like they can go in the .h file
#end
// again in the .m file (what's the purpose of private?)
#interface MyClass (Private)
// some method declarations
#end
This is just a normal class interface, inheriting from NSObject, where you declare ivars, properties and methods
// in the .h file
#interface MyClass : NSObject
// ...
#end
The following two are categories, which allow you to add methods to a class. It is not a subclass however (do not declare a method with the same name, as you won't be able to access the original one). If you have a named category of the interface (like #interface MyClass (Private)), then the implementation should be provided in #implementation MyClass (Private), in the case of unnamed categories (also called extensions), the implementation can be provided as usual. Note that extensions also allow you to add ivars to the class while (named) categories do not.
// in the .m file (what's the purpose of the parens?)
#interface MyClass ()
// more property declarations which seem like they can go in the .h file
#end
// again in the .m file (what's the purpose of private?)
#interface MyClass (Private)
// some method declarations
#end
It is used to declared private methods.
This response explain this in details: What are best practices that you use when writing Objective-C and Cocoa?
What ever goes in the .m file is private. the parens are for categories so you can segment your code into categories to make it more readable. because the code is in .m and private, they called the category Private.

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.

Cocoa: Build Warning that s Forward Declared Class's and #interface May not Exist

I am trying to build the Clustering Plug in my project under Leopard. I have following two questions.
In the project an interface class is defined as
#interface ClusteringController : NSWindowController
{
.......
.....
....
}
#end.
And this class is used in implementation class using forward declaration:
#class ClusteringController;
then in one function it is used as:
- (long) filterImage:(NSString*) menuName
{
ClusteringController *cluster = [[ClusteringController alloc] init];
[cluster showWindow:self];
return 0;
}
When I build this project it produces the warning:
warning: receiver 'ClusteringController' is a forward class and corresponding #interface may not exist
Also there is one more warning produced:
warning: no '-updateProxyWhenReconnect' method found
This warning is coming for the following line of code:
if(delegate) [delegate updateProxyWhenReconnect];
Can anybody help me to overcome these warnings?
A forward declaration is used when the header file will be imported after the interface. It looks to me that you've used the #class directive after the interface for the class itself.
The normal use of a forward class declaration looks like this:
#import "SomeSuperClass.h"
#class Forwardclass;
#interface SomeClass : SomeSuperClass
{
Forwardclass anIvar;
}
#property Forwardclass anIvar;
#end
#import "SomeClass.h"
#import "ForwardClass.h"
#implementation SomeClass
#synthesize anIvar;
-(void) setAnIvar:(ForwardClass *) aForwardClass;
#end
The #class directive is never used in an implementation (.m) file.
That's not what #class is for.
You use #class in the header file for another class, to tell the compiler that the class you're declaring does exist. Without it, the compiler would not know that that's a class name, and when you declare a variable as holding a pointer to an instance of that class, the compiler would think that you're just making up words. Using #class is called forward-declaring the class.
Your situation is different. You're in the implementation file for that class.
What the compiler needs from you now is the class's #interface. The warning is telling you that the compiler needs an #interface, but you haven't given it one (so, as far it knows, the #interface “may not exist”).
Normally, you would have written the #interface in a header file; how now to get it into the implementation file?
That's where the preprocessor comes in, with its #import directive. At the top of the implementation file (ClusteringController.m), import the header file:
#import "ClusteringController.h"
The preprocessor will replace this with the contents of that file, then hand the preprocessed code to the compiler, which will see the #interface there.

Category usage in 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.