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.
Related
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Protected methods in objective-c
The way to declare private properties is simple.
You declare that in extension that's declared in .m files.
Say I want to declare protected properties and access it from the class and subclass.
This is what I tried:
//
// BGGoogleMap+protected.h
//
//
#import "BGGoogleMap.h"
#interface BGGoogleMap ()
#property (strong,nonatomic) NSString * protectedHello;
#end
That one is compile. Then I added:
#import "BGGoogleMap+protected.h"
#implementation BGGoogleMap ()
-(NSString *) protectedHello
{
return _
}
#end
Problem starts. I can't implement class extension outside the original .m files it seems. Xcode will demand something inside that bracket.
If I do
#import "BGGoogleMap+protected.h"
#implementation BGGoogleMap (protected)
-(NSString *) protectedHello
{
return _
}
#end
I cannot access the ivar of _protectedHello declared in BGGoogleMap+protected.h
Of course I can use regular category rather than extension, but that means I can't have protected properties.
So what should I do?
The Objective-C Programming Language says this:
Class extensions are like anonymous categories, except that the methods they declare must be implemented in the main #implementation block for the corresponding class.
So you could just implement your class extension's methods in the class's main #implementation. That is the simplest solution.
A more complicated solution is to declare your “protected” messages and properties in a category, and declare any instance variables for that category in a class extension. Here's the category:
BGGoogleMap+protected.h
#import "BGGoogleMap.h"
#interface BGGoogleMap (protected)
#property (nonatomic) NSString * protectedHello;
#end
Since a category cannot add an instance variable to hold protectedHello, we need a class extension also:
`BGGoogleMap_protectedInstanceVariables.h'
#import "BGGoogleMap.h"
#interface BGGoogleMap () {
NSString *_protectedHello;
}
#end
We need to include the class extension in the main #implementation file so that the compiler will emit the instance variable in the .o file:
BGGoogleMap.m
#import "BGGoogleMap.h"
#import "BGGoogleMap_protectedInstanceVariables.h"
#implementation BGGoogleMap
...
And we need to include the class extension in the category #implementation file so that the category methods can access the instance variables. Since we declared the protectedHello property in a category, the compiler will not synthesize the setter and getter method. We have to write them by hand:
BGGoogleMap+protected.m
#import "BGGoogleMap+protected.h"
#implementation BGGoogleMap (protected)
- (void)setProtectedHello:(NSString *)newValue {
_protectedHello = newValue; // assuming ARC
}
- (NSString *)protectedHello {
return _protectedHello;
}
#end
Subclasses should import BGGoogleMap+protected.h to be able to use the protectedHello property. They should not import BGGoogleMap_protectedInstanceVariables.h because the instance variables should be treated as private to the base class. If you ship a static library without source code, and you want users of the library to be able to subclass BGGoogleMap, ship the BGGoogleMap.h and BGGoogleMap+protected.h headers, but don't ship the BGGoogleMap_protectedInstanceVariables.h header.
I wish I could tell you otherwise but you just can't. See this question for more information: Protected methods in Objective-C.
I am not sure, what you want to do? Something Hacking or Cracking of Data Abstraction out of OOPS concept?
Extensions are used to add properties. You have successfully added private property as in
#import "BGGoogleMap.h"
#interface BGGoogleMap ()
#property (strong,nonatomic) NSString * protectedHello;
#end
What are you doing in this ?
#import "BGGoogleMap+protected.h"
#implementation BGGoogleMap ()
-(NSString *) protectedHello
{
return _
}
#end
You have extended a class, now you are again implementing same class !!! Twice!!! And category only comes with .h file. I guess you are creating yourself a .m file, that not acceptable.
Private properties cant be accessed outside the class, it can be accessed only from the base class or subclass. That is what the error is.
I can't implement class extension outside the original .m files it seems.
Yes this is abstraction and data hiding of Objective-c !!!
In an Objective-C class I have a #private ivar that uses an enum of the form:
typedef NS_ENUM(NSInteger, PlayerStateType) {
PlayerStateOff,
PlayerStatePlaying,
PlayerStatePaused
};
However, I include this definition in the header file of that class (since it's used in it). This effectively makes the type public, which isn't what I intended. How can I make this enum type private?
Adding my comment as an answer.
You can add this in your .m class so that while importing it is not shared with other classes. You can just add it below your import statements. If the params of this type are used only in this .m class, you can declare that also in this .m file.
Your .m class will look like,
typedef NS_ENUM(NSInteger, PlayerStateType) {
PlayerStateOff,
PlayerStatePlaying,
PlayerStatePaused
};
#interface ViewController () //Use an extension like this in .m class
#property (nonatomic) PlayerStateType param;
#end
Define it in .m file & declare your privare ivar in controller category in .m file. To know about controller category take a look at Difference between #interface definition in .h and .m file.
I've been trying to find a workaround to declare #protected properties in Objective-C so only subclasses in the hierarchy can access them (read only, not write).
I read that there is no documented way of doing this so I thought of this workaround and I wanted to ask StackOverflow's opinion about it.
Every custom class at the top of the hierarchy contains three classes, one implementation and two interfaces.
Let's name them:
ClassA.h
ClassA_protected.h
ClassA.m
Then any subclass of this ClassA would be as usual:
ClassB.h
ClassB.m
First I created the interface ClassA.h where I declare a protected int variable so any subclass of ClassA can have access to it:
#interface ClassA : NSObject{
#protected
int _myProtectedInt;
}
#end
Next step is the workaround I was talking about. However, once you read it you will see that it is quite straight forward. I declared a second interface called ClassA_protected.h which actually works as an extension of ClassA.h and allows us to tag the property as readonly:
#import "ClassA.h"
#interface ClassA ()
#property (nonatomic , readonly) int myProtectedInt;
#end
Last step of preparing the protected hierarchy is to declare its implementation in ClassA.m where we only synthesize our property:
#import "ClassA_protected.h"
#implementation ClassA
#synthesize myProtectedInt = _ myProtectedInt;
#end
This way, every class that needs to be a subclass of ClassA.h, will import ClassA_protected.h instead. So a child like, for example ClassB.h, would be as follows:
#import "ClassA_protected.h"
#interface ClassB : ClassA
#end
And an example of accessing this property from ClassB.m's implementation:
#implementation ClassB
-(void) method {
//edit protected variable
_myProtectedInt= 1;
//normal access
self.muProtectedInt;
}
#end
Sure, that works fine. Apple uses the same approach for example in the UIGestureRecognizer class. Subclasses have to import the additional UIGestureRecognizerSubclass.h file and override the methods that are declared in that file.
For simple "properties" just use ivar instead. That's as good as properties for all practical purposes.
Moreover, the default is already protected.
If you ask for opinion, this is mine: If one decides to mutate your
_myProtectedInt
he will probably succed anyway, because it's definitely possible with Objective-C runtime. Except this, your solution is quite OK.
Import the protected header in the implementation only. e.g.
ClassB.h
#import "ClassA.h"
#interface ClassB : ClassA
#end
ClassB.m
#import "ClassA_protected.h"
#implementation ClassB
#end
And in a framework the protected header should be marked project so it is not included in the public headers of the framework. Apple usually use the suffix _Internal.h for their protected methods.
For init or overriding a lazy loaded get property you would need direct access to the #proteced ivar, however for your use it would be better to redeclare the property as readwrite instead then you can take advantage of any features of the setter, atomicity for example.
why do I see #interface twice( inside .h and .m files in this UIViewController files I've created. the one in the .m seems to be like a constructor. is it?
.h file
#interface BlackTimer : UIViewController
#end
.m file
#interface ViewController ()
#end
usually in the .m file you put all the declarations for private methods
it's a good use to write the word "private" (or something similar) like this:
#interface ViewController (private)
-(void)myPrivateMethod;
#end
The #interface in the .m file is called a class extension. Here is a good link explaining it. Hope this helps.
And here is the Apple documentation on class extensions.
The #interface ViewController () definition in the implementation file (.m) is an anonymous Category. It allows to define ivars, properties and messages your class implements without exposing them to other objects importing your public interface (.h).
Normally we use
#interface interface_name : parent_class <delegates>
{
......
}
#end
method in .h file and in .m file we synthesis the properties of variables declared in .h file.
But in some code, this #interface.....#end method is kept in the .m file also. What does it mean? What is the difference between them?
Also give some words about getters and setters for the interface file that is defined in .m file...
It's common to put an additional #interface that defines a category containing private methods:
Person.h:
#interface Person
{
NSString *_name;
}
#property(readwrite, copy) NSString *name;
-(NSString*)makeSmallTalkWith:(Person*)person;
#end
Person.m:
#interface Person () //Not specifying a name for the category makes compiler checks that these methods are implemented.
-(void)startThinkOfWhatToHaveForDinner;
#end
#implementation Person
#synthesize name = _name;
-(NSString*)makeSmallTalkWith:(Person*)person
{
[self startThinkOfWhatToHaveForDinner];
return #"How's your day?";
}
-(void)startThinkOfWhatToHaveForDinner
{
}
#end
The 'private category' (the proper name for a nameless category is not 'private category', it's 'class extension') .m prevents the compiler from warning that the methods are defined. However, because the #interface in the .m file is a category you can't define ivars in it.
Update 6th Aug '12: Objective-C has evolved since this answer was written:
ivars can be declared in a class extension (and always could be - the answer was incorrect)
#synthesize is not required
ivars can now be declared in braces at the top of #implementation:
that is,
#implementation {
id _ivarInImplmentation;
}
//methods
#end
The concept is that you can make your project much cleaner if you
limit the .h to the public interfaces of your class, and then put
private implementation details in this class extension.
when you declare variable methods or properties in ABC.h file , It
means these variables properties and methods can be access outside the
class
#interface Jain:NSObject
{
NSString *_name;
}
#property(readwrite, copy) NSString *name;
-(NSString*)makeSmallTalkWith:(Person*)jain;
#end
#Interface allows you to declare private ivars, properties and
methods. So anything you declare here cannot be accessed from outside
this class. In general, you want to declare all ivars, properties and
methods by default as private
Simply say when you declare variable methods or properties in ABC.m
file , It means these variables properties and methods can not be
access outside the class
#interface Jain()
{
NSString *_name;
}
#property(readwrite, copy) NSString *name;
-(NSString*)makeSmallTalkWith:(Person*)jain;
#end
you can even create other classes in .m file,
for instance other small classes which inherit from the class declared in .h file but having some slight different behaviour.
You could use this in a factory pattern