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;
}
Related
An external framework I'm using in my application defines theClass whose internal structure is opaque.
Its instance variables are not meant to be accessed directly.
#class TheClassPrivateVars;
#interface TheClass : NSObject
{
#private
TheClassPrivateVars *_theClassPriv;
}
#end
The framework public interface is not as complete as it should be and (at my I own risk) I want to read one of the private variables of myClass.
Fortunately the framework is supplied with complete source code so I have access to the definition of TheClassPrivateVars:
#interface TheClassPrivateVars : NSObject
{
int thePrivateInstanceVar; // I want to read this!
//
// other properties here...
//
}
#end
I've made a header file with the above code and included it just in the source file where the "abusive access" have to happen.
theValue = instanceOfTheClass->_theClassPriv->thePrivateInstanceVar;
Unfortunately _theClassPriv is declared as #private.
Is there any way I can get around it without modifying the original header file ?
TheClassPrivateVars* private = [instanceOfTheClass valueForKey:#"_theClassPriv"];
EDIT: or using key path:
theValue = [[instanceOfTheClass valueForKeyPath:"_theClassPriv.thePrivateProperty"] integerValue];
#import <objc/runtime.h>
TheClassPrivateVars *_data;
object_getInstanceVariable(self, "_theClassPriv", (void**)&_data);
Couldn't you just do this?
Would probably be a good idea if it is an Apple framework to tell us what framework and what property you are talking about, for some educated guesses exactly how foolish or not it is to access that private property. After all, private properties can be gone tomorrow. And you won't be able to get your app on the App Store easily.
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.
Edit 2: In addition to Kurt's solution, there is one more way to do it. Take a look at the end of this page, just before comments: http://www.friday.com/bbum/2009/09/11/class-extensions-explained/
Edit: It seems class methods in a class category cannot access private members such as ivars and private methods that are implemented through class extensions.
I hope this question is not asked and answered before, but I could not find one as both stackoverflow and Google search spams my browser window with kinds of questions that ask to access an ivar directly from a class method, which is clearly not my intention.
Straight to the problem, I'll provide a piece of code, which summarizes what I'm trying to accomplish:
XYZPerson.h:
#interface XYZPerson : NSObject
#property (weak, readonly) XYZPerson *spouse;
#end
XYZPersonMariage.h:
#interface XYZPerson (XYZPersonMariage)
+(BOOL)divorce:(XYZPerson *) oneOfSpouses;
#end
XYZPersonMariage.m
+(BOOL)divorce:(XYZPerson *)oneOfSpouses
{
XYZPerson *otherSpouse = [oneOfSpouses spouse];
if(otherSpouse != nil)
{
oneOfSpouses->_spouse = nil;
otherSpouse->_spouse = nil;
return true;
}
return false;
}
I first thought that maybe an ivar is not automatically synthesized for a property flagged readonly, but it is indeed synthesized.
So, what paths can I take to get the job done?
Your method +[XYZPerson divorce:] is defined in XYZPersonMarriage.m, which is a different compilation unit than XYZPerson.m where the rest of XYZPerson is implemented.
Because of this, when compiling +divorce:, the compiler doesn't know there's an implicitly synthesized _spouse variable. For all it knows, the property could be backed by a method -spouse that you implemented.
Ways to get around this:
Move the implementation of +divorce into XYZPerson.m.
Don't access ivars directly, but do the work via real methods. They don't have to be part of the usual public interface of the class; they can be exposed via a separate header file that only XYZPersonMarriage.m imports. Search for "Objective-C private method" for more discussion on the pros and cons of that pattern.
In my iPhone application I have multiple class files, I have my main application's class files, then I have my UIView class files. I have a simple -(void) method declared in my UIView class files, how can I access it from my main applications class files?
A bit more detail: In my application a video is played, when this video finishes playing a notification is sent and actions are preformed, which I have already successfully set up, however when the movie finishes I would like a method declared in another class file to be preformed. If the method was declared in the same class file I would simply use this code: [self mySimpleVoidMethod]; But obviously this doesn't work If the method is declared in a different class file. I believe it is possible to access a method declared in a different class file, but I just haven't got a clue about how to do it. Sorry if I'm using completely incorrect terms to name things. But I am relatively new to programming all together.
You've got a couple of options, depending on your setup. Here are a few:
1) Add a reference to the class with the function (the callee) as a property in the caller's class:
Caller.h
#interface Caller : SomeObject {
Callee *myCallee;
...
}
#property(nonatomic, retain) Callee *myCallee;
Caller.m
#synthesize myCallee;
-(void)someAction {
[myCallee doSomething];
}
Something that sets up Caller after initializing both classes:
caller.myCallee = callee;
2) Use another notification event, like it looks like you already know how to do.
3) Use a protocol if you've got a bunch of different classes that Caller might need to call that all support the same method:
DoesSomething.h
#protocol DoesSomething
-(void)doSomething;
#end
Callee.h
#interface Callee : NSObject<DoesSomething> { // NSObject or whatever you're using...
...
}
-(void)doSomething;
Caller.h
#interface Caller : SomeObject {
id<DoesSomething> *myCallee;
...
}
#property(nonatomic, retain) id<DoesSomething> *myCallee;
... Then as per example 1.
4) Use performSelector to send a message to the class.
Caller.h
#interface Caller : NSObject {
SEL action;
id callee;
}
-(void)setupCallbackFor:(id)target action:(SEL)callback;
Caller.m
-(void)setupCallbackFor:(id)target action:(SEL)callback {
callee = target;
action = callback;
}
-(void)someAction {
if([callee respondsToSelector:action]) {
[callee performSelector:action];
}
I'm sure there are other ways, and there are pros and cons to each of these, but something in there should fit your needs and/or give you enough to scan the documentation to fill in any gaps...
I did a blog post a few weeks ago that outlines one way to do this. It is similar to the previous answers, and includes some sample code you can download and look at. It is based on using table view controllers, but you should be able to adapt the ideas to your application without too much difficulty.
Passing values and messages between views on iPhone
You'll need an instance of the other class, accessible from the code that runs when the movie finishes. Often, this is accomplished by storing an instance of the other class as a field in the class, set either via a "setter", or during construction. You could also use key-value observing, watching a key representing the playstate of the movie; an instance of the other class can register to observe the changes to this key.
Specifically for patterns using UIView, your UIViewController for the view will have access to it (through the view method). If your "main application's class files" have a pointer to the controller - which they probably will, setup via Interface Builder - then that's an easy way to get to a UIView instance.
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 .