I have created a subclass of NSObject to be used as a Model.
Within this I have some public methods which are accessible outside of this.
Within the implementation file I also have some Private methods like this:
+(void)publicMethod {
// I am public
}
-(void)privateMethod {
// I am private
}
However, I am unable to call the private method from within the public method. I.e. the following does not work:
[self privateMethod];
Is this expected behaviour? Should all the methods in my NSObject subclass (used as a model) be public?
Edit: Remark that this answer is not complete. The question deals with instance methods calling class methods, which I did not catch when I was writing the answer. But even though it does not answer the question, it's still an example on how to mimic the use of public and private methods in Objective-C.
In Objective-C there is no such thing as public and private methods, but you can "hide" instance methods by not putting them in the public header file.
This is the way Apple does it. NSObject, UIView, NSString, etc., has a bunch of "private" methods. That being they are not private. They are simply not exposed in the header file you include in your app.
If your class has an instance or class method that is not visible to the outside world, you can still just declare it yourself - if you know the prototype - in your code and then access them.
The way I do it is by creating two header files. One for public methods and one for private. Let's say this is a public library, I will only include the header files with the "public" methods for other developers to use.
On the other hand, inside my project, I can include the "private" header, which holds both the private and the public methods, and I have access to everything I need.
An example is this class, which has to methods: foo and bar. foo is public and bar is private.
The "public" header - which is called MyCustomClass.h would look like this:
#interface MyCustomClass
- (void)foo;
#end
Then I create a class extension in another header file - which is called MyCustomClass+Private.h, and it looks like this. This is also a good place to put your instance variables, so they too won't be exposed to the "outside world".
#import "MyPublicClass.h"
#interface MyPublicClass () {
NSInteger _myIvar;
}
- (void)bar;
#end
Now in the class implementation - which is called MyCustomClass.m I implement everything. Remark that I am including the private header file.
#import "MyPublicClass+Private.h"
#implementation MyPublicClass
- (void)bar { /* Private Method */
/* Do something */
}
- (void)foo {
[self bar];
}
#end
Solution
Now whenever I subclass MyCustomClass I first and foremost also create a private header for that class - which imports the private header of it's superclass. The public header of the subclass only imports it's superclass's public header.
This way both foo and bar are exposed to subclasses, but not to outsiders - as you would not put your private headers in your library - if that's what you are making.
A remark on your example
In the old days, you could do what you do, and get away with a compiler warning. But nowadays ARC is not satisfied, and throws a compiler error. This is because ARC needs to know the return type, so it can do release/retain on it, in order to properly manage your app's memory.
Simpler solution
A simpler way of doing it could also be to just throw the superclass extension - with the superclass's "private" method prototypes - in your subclass's implementation. But this has the drawback of you needing to go through every place you put the extension if you change your superclass's behaviour down the road. So I wouldn't recommend it.
Final
Hope this clarifies and helps you out. Good luck!
Your publicMethod is a class method. So self is the class in this method, not an instance. And the class doesn't implement privateMethod because it's an instance method.
Related
I am currently in the process of creating an objective c framework for iOS to help facilitate the interaction between an API and a developer. As part of this, I return various arrays of readonly objects that a developer can use to display information to the user. However, I would like to ensure that the objects displayed to the user come only from the framework and can not be instantiated by the developer using the framework.
My current implementation uses a custom constructor initializer that takes JSON from the api to instantiate itself. The only way that I am aware of accessing my custom constructor initializer is by putting its definition in the header file which makes it not only accessible to myself, but also the developer. I am aware that I can throw an inconsistency exception when the user tries to use the default constructor initializer, -(id)init;, but I can not stop them from creating their own JSON string and calling my custom constructor initializer.
Am I taking the correct approach to securing my private framework from interference from the developer using it? How else can I get around this to ensure the validity of data in these objects?
Source: Is it possible to make the -init method private in Objective-C?
You are correct that Objective-C doesn't allow for truly private methods by it's very nature, due to its dynamic dispatch system. However, assuming your question is not about true security, rather simply making it difficult to use the framework in an incorrect way, you have a few options.
A simple, common solution would be to put the declarations for methods you don't want to expose publicly in a category in a separate header file. You can still put these methods' implementations in the main implementation file for the class. So, a header with something like this:
// MyClass+Private.h
#interface MyClass (Private)
- (void)aPrivateMethod;
#end
Then, in your own source files where you need to access those private methods, you simply import MyClass+Private.h.
For a framework, you can set each header file to be Public or Private. Private headers will not be copied into the framework bundle, and therefore won't be visible to users of the Framework. You do this by opening the Utilities pane in Xcode (the right-side slide out pane), selecting the header in question, then choosing Private in the second column of the relevant row under "Target Membership".
Based on Andrew Madsen's solution, I ended up using was to have two different header files for each object; One that was public, and one that was private. The public header contains only the information needed by the developer to access the read only properties. Then my private header imports the public header and also contains a category with all the method calls I need to use within the SDK (including the initializer). I then import the private header into my implementation. The structure looks like this:
Public Header MyObject.h
#import <Foundation/Foundation.h>
#interface MyObject : NSObject
#property (nonatomic, retain, readonly) NSString *myValue;
#end
Private Header MyObject+Private.h
#import "MyObject.h"
#interface MyObject (Private)
+(MyObject*)MyObjectFromJSONString:(NSString*)JSONString;
-(id)initWithJSON:JSONString:(NSString*)JSONString
#end
Private Implementation MyObject.m
#import "MyObject+Private.h"
#implementation MyObject
#synthesize myValue = _myValue; //_myValue allows local access to readonly variable
- (id)init {
#throw [NSException exceptionWithName:NSInternalInconsistencyException reason:#"-init is not a valid initializer for the class MyObject" userInfo:nil];
return nil;
}
+(MyObject*)MyObjectFromJSONString:(NSString*)JSONString;
{
return [[MyObject alloc]initWithJSON:JSONString];
}
-(id)initWithJSON:JSONString:(NSString*)JSONString
{
self = [super init];
if(self){
//parse JSON
_myValue = JSONString;
}
return self;
}
I'm writing a library, which will potentially be used by people that aren't me.
Let's say I write a class:
InterestingClass.h
#interface InterestingClass: NSObject
- (id)initWithIdentifier:(NSString *)Identifier;
#end
InterestingClass.m
#interface InterestingClass()
- (void)interestingMethod;
#end
#implementation InterestingClass
- (id)initWithIdentifier:(NSString *)Identifier {
self = [super init];
if (self) {
[self interestingMethod];
}
return self;
}
- (void)interestingMethod {
//do some interesting stuff
}
#end
What if somebody is using the library later down the line and decides to create a subclass of InterestingClass?:
InterestingSubClass.h
#interface InterestingSubClass: InterestingClass
#end
InterestingSubClass.m
#interface InterestingSubClass()
- (void)interestingMethod;
#end
#implementation InterestingSubClass
- (void)interestingMethod {
//do some equally interesting, but completely unrelated stuff
}
#end
The future library user can see from the public interface that initWithIdentifier is a method of the superclass. If they override this method, they'll probably assume (correctly) that the superclass method should be called in the subclass implementation.
However, what if they define a method (in the subclass private interface) which inadvertently has the same name as an unrelated method in the superclass 'private' interface? Without them reading the superclass private interface, they won't know that instead of just creating a new method, they've also overridden something in the superclass. The subclass implementation may end up getting called unexpectedly, and the work that the superclass is expecting to be done when calling the method will not get done.
All of the SO questions I've read seem to suggest that this is just the way that ObjC works and that there isn't a way of getting around it. Is this the case, or can I do something to protect my 'private' methods from being overridden?
Alternatively, is there any way to scope the calling of methods from my superclass so I can be sure that the superclass implementation will be called instead of a subclass implementation?
AFAIK, the best you can hope for is declaring that overrides must call super. You can do that by defining the method in the superclass as:
- (void)interestingMethod NS_REQUIRES_SUPER;
This will compile-time flag any overrides that don't call super.
For framework code a simple way to deal with this is to just give all of your private methods a private prefix.
You'll often notice in stack traces that the Apple frameworks call private methods often starting with an under bar _.
This would only really be a real concern if you are indeed providing a framework for external use where people can not see your source.
NB
Don't start your methods with an under bar prefix as this convention is already reserved
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.
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 .
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.