Question

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?

Was it helpful?

Solution

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".

OTHER TIPS

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;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top