Objective-C: accessing instance variables declared as #private - objective-c

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.

Related

How Exactly To Use a Global Variable?

I'm a beginner with Objective-C, and am trying to use a global variable. I know that this question has been asked a hundred times, but none of the answers have worked for me. I'm trying to declare a BOOL variable in one class, and check its value in another. This is what I'm working with:
SController.h:
#interface SController : UIViewController {
BOOL leftSide;
BOOL rightSide;
}
SController.m:
- (void)viewDidLoad {
leftSide = YES;
rightSide = YES;
}
Now, for the class I'm trying to access the value of the BOOLs in:
#import "SController.h"
#interface VViewController : UIViewController
{
}
And VViewController's .m:
- (void)viewDidLoad {
// See what the BOOL values from SController are.
}
What I've tried:
Going off of the previous related questions on here, I've tried putting "extern" in front of the BOOLs declaration in SController.h, but that did not work. I tried simply importing the SControllers header file into VViewController, and that did not work either. I'm very new to Objective-C and programming in general, so I'm having a tough time wrapping my head around basic concepts like this. I understand the potential issues surrounding using a global variable, but this program is very small and for personal use. If anyone can show me what to change to make this happen, that would be great.
Like the others said, don't use a global variable for that (and most other) purpose.
You created iVars and in order to access them, you need to expose them to other objects.
You generally do that by defining #properties in your SControllers header file. When doing that, you don't need to create iVars yourself, they are created implicitly. And methods to access the iVars are also automagically created (getters and setters).
Your SControllers header could look something like this:
#interface SController: UIViewController
//no need to declare the iVars here, they are created by the #property definitions
#property (nonatomic, assign) BOOL leftSide;
#property (nonatomic, assign) BOOL rightSide;
#end
In your other viewController you need a reference to the instance of SController you previously created and want to "talk" to (it is important you understand this), then you could access the instance variable through the generated getter/setter methods like so:
//this is "dot notation", the first line would be equivalent
//to writing: [sControllerInstance setLeftSide: YES]
sControllerInstance.leftSide = YES;
BOOL valueRightSide = sControllerInstance.rightSide;
Please read up on: objective-c properties, getters/setters and dot notation.
You will find plenty of information on google and SO
I know this is not the answer you're looking for, but try rethinking your app. Global variables is not the best way to go for Object oriented programming.
Create GlobalVariable.h header class file and defined following externs as follows
extern NSString * googleURL;
And then in your implementation GlobalVariable.m file
#import "GlobalVariable.h"
NSString * googleURL = #"www.google.co.uk";
And then import the class wherever you want to use it across.
By default the variables (as defined in your code) are protected. You can add the #public keyword before the 2 variables to make them public but it's not recommended. Generally you want to expose those as properties using the #property keyword
Example:
#interface SController : UIViewController {
#public
BOOL leftSide;
BOOL rightSide;
#protected
//other protected variables here
}

Prevent instantiation of readonly objects from framework

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;
}

Accessing ivar of an instance of the same class in a class 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.

Global Property in Objective C

I have an enum defined in the Constants.h file this way:
typedef enum {
CalendarTypeMonth = 0,
CalendarTypeWeek
} CalendarType;
Then in my view controller I determine what the calendar type should be and store it in a property this way:
#property (nonatomic) CalendarType myCalendarType;
Now I want all the classes in my project have access to the calendar type. How can I set this property to be global/extern so that all classes can read this?
EDIT: I know the definition of the enum will be available across the project. But what I am interested in is the value of myCalendarType. How can I access the value of myCalendarType across all classes?
You can declare class method to access static variable.
Add such code to your implementation file:
static MyStaticType staticVar = MyStaticTypeDefault;
+(BOOL)myStaticVar
{
return staticVar;
}
+(void)setMyStaticVar:(MyStaticType)newValue
{
staticVar = newValue;
}
And create declarations for this methods in interface file.
This is much better then moving all static values to AppDelegate.
Anyway, a lot of variants are possible - for example, you can create singletone to store some settings of application or use CoreData.
In your [Project Name]_Prefix.pch file, you can add this statement:
#import "Constants.h"
In so doing, you'll make your enum available to every file in the project.
EDIT:
To access the value, I suggest making it a global property of your application delegate. To take it a step further, you can make your application delegate a method of NSObject using a category so it might look something like:
CalendarType current = [self appDelegate].currentCalendarType
Observe that your property is now a globally gettable/settable property.

Is it possible to declare a method as private in Objective-C?

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 .