So You Thought You Had Privacy?
Of all the tenets of Objected-Oriented Programming, it might be Encapsulation that I like best. Keep details only pertinent to the logic internals of a class hidden, while publicly needed methods and data are globally accessible. It keeps clutter in your API to a minimum, reduces unnecessary coupling between classes, and makes code less error-prone (there are fewer things that can go wrong when other people use your code, if you only give them access to what you think they need).
And then, there's Objective-C. The loosest of the loose. While I love coding in Objective-C, because it means I'm writing software for iOS, Objective-C is an absolute nightmare in terms of many, many things other languages do to keep you from shooting yourself in the foot. From the compiler letting you send messages that aren't appropriate for the target object (with only a warning), to method swizzling, to class dumping your binary's headers, Objective-C has got more holes than Swiss cheese. As a man who once programmed in Ada, it's a little hard to take sometimes.
Here's another perfect example. In most languages, you have access modifiers such as public, protected, and private. Only public members are visible to other classes (not including subclasses), and the default in most languages is not public. But, then there's how Objective-C works. In Objective-C, you can get access to any member variable (aka ivar), regardless of its accessibility modifier. Sure, the modifier affects how easy it is to get at the data. But, not whether it's accessible.
Consider this example class:
@interface Foo : NSObject {
@private
BOOL isFoo;
struct {
int x;
int y;
int z;
} _coordinate;
int counter;
}
@end
The variable _coordinate is private, right? We cannot do this:
Foo f = [[Foo alloc] init]; int x = f._coordinate.x; // not a property ... won't compile! int y = f->_coordinate.y; // private ... won't compile!
But, that is far from the end of the story. With Objective-C, we can use the runtime APIs to get at almost anything we like. The runtime can even be used to add ivars or methods to a class at runtime, or switch the default implementation of a class method for a new one (like overriding a method without having to subclass it, or even have its source code. In this case, we can define a nice helper method to get ivars from a class, using their name. And, of course, if someone runs class-dump on your code, they can get headers reverse-engineered with all your class variables' names!.
#import <objc/runtime.h>
- (void *) instanceVariableForObject: (id)obj andName: (NSString *)name {
if (name != nil) {
Ivar ivar = object_getInstanceVariable(obj, [name UTF8String], NULL);
if (ivar != nil) {
return (void *)((char *)obj + ivar_getOffset(ivar));
}
}
return NULL;
}
We then get full access to _coordinate like this:
// declare a matching struct type to facilitate access to the data
typedef struct {
int x;
int y;
int z;
} CoordinateType;
Foo* f = [[Foo alloc] init];
CoordinateType c = *(CoordinateType*)[self instanceVariableForObject: f
andName: @"_coordinate"];
NSLog(@"result = {%d, %d, %d}",
c.x, c.y, c.z);
See? Your privacy is merely an illusion! Protect yourself accordingly.
Posted at 01:53AM Jul 29, 2012 by Nathan in Coding | Comments[0]
HTML allowed/encouraged in comments! Your email address is only used to notify you when your comment is accepted or rejected, and if there are more comments. I do not sell email addresses, or record them for any other purpose (notice the lack of advertising anywhere on my website).
