2
votes

I've created two classes with methods with same name. In one of them it is private, in another - public. Then somewhere on code i write this:

-(void) doMagic:(id) object {
    [(ClassA*)object doSmth];
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    // Insert code here to initialize your application
    ClassB * objB = [[ClassB alloc] init];
    [self doMagic:objB];
}

In console i see this: 2012-04-25 23:41:28.183 testmagic[558:403] classB - doSmth

Here's classes' sources:

//.h
@interface ClassA : NSObject
-(void) doSmth;
@end
//.m
@implementation ClassA
-(void)doSmth {
    NSLog(@"classA - doSmth");
}
@end

//.h
@interface ClassB : NSObject


@end
//.m
@interface ClassB ()
-(void) doSmth;

@end;

@implementation ClassB
- (void)doSmth {
    NSLog(@"classB - doSmth");
}
@end

I know, it's because of "message" nature of methods in Obj-C, and at runtime class possibly do not know which of it's methods are private or public, but here's the question:

How can i make really private method? I heard that with decompiling it's possible to see methods names, so someone can just use my private API. How can i prevent it?

4
There isn't a way to make a truly private method. If your object responds to a message, then it responds. See: stackoverflow.com/questions/172598/… and stackoverflow.com/questions/2158660/… - jscs
So i should some how check, that message was send from this object? Maybe i should make some boolean variable and set it to YES before using method? I found one more thing. You can also become an observer for keypath, where key path some private property. It's stunning unsafe language. But cool, anyway. - Nikita Ilyasov

4 Answers

2
votes

The runtime cannot call what it never knows about. The approach I typically take is to use a static function:

MONObject.h

@interface MONObject : NSObject
// ...
@end

MONObject.m

// 'private' methods and ivars are also visible here
@interface MONObject()
// ...
@end

// typically here:
static void fn(MONObject * const self) {
    NSLog(@"%@", [self description]);
}

@implementation MONObject
// ...

// sometimes here:
static void fn2(MONObject * const self) {
    NSLog(@"%@", [self description]);
}

@end
1
votes

A workaround to your problem could be to use a proxy/façade class which internally aggregates an instance of your private class. E.g.:

// .h
@interface FoobarFacade: NSObject
- (void)publicMethod;
@end

// .m
@interface FoobarFacade ()
{
    Foobar* impl;
}
@end

@interface Foobar: NSObject
- (void)secretMethod;
@end

@implementation Foobar
- (void)secretMethod { NSLog(@"foobar secret method"); }
@end

@implementation FoobarFacade
- (void)publicMethod {
     NSLog(@"façade public method");
     [impl secretMethod];    // calling into the secret method
}
@end

Of course this isn't 100% safe either, the runtime puts no barriers as others already told.

0
votes

Right now you can't have truly private methods. When you are declaring a method in a class extension in the .m file you are just hiding it from being exposed in the public header fle. What you are doing now is considered good design because you are hiding the method from the header file which means people would have to go to some length to find those hidden methods, but they can still find them.

Basically the rule I follow is to put as little as I can into the public header as possible and to put everything else into a class extension. This is all you can really do for now.

-1
votes

If you declare the method in the .h file is public. If you want private visibility you have to declare the method in your .m for example:

@interface ClassB (Private_Methods)
- (void)doSmth;
@end

@implementation ClassB

//Rest of .m