2

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?

Nikita Ilyasov
  • 500
  • 2
  • 14
  • 3
    There isn't a way to make a _truly_ private method. If your object responds to a message, then it responds. See: http://stackoverflow.com/questions/172598/best-way-to-define-private-methods-for-a-class-in-objective-c and http://stackoverflow.com/questions/2158660/why-doesnt-objective-c-support-private-methods – jscs Apr 25 '12 at 20:02
  • 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 Apr 25 '12 at 20:10

4 Answers4

2

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
justin
  • 104,054
  • 14
  • 179
  • 226
  • Why should it be static? I mean it's a c-style function. Is it possible to call it from outside, if it's not static? – Nikita Ilyasov Apr 25 '12 at 20:27
  • 1
    it's `static` because it is intended to be private, and you don't want conflicts when linking. if it were not static, it would have default visibility, so somebody could call it if they knew the prototype. – justin Apr 25 '12 at 20:29
  • Thank you. Looks like it's the only solution. – Nikita Ilyasov Apr 25 '12 at 20:32
  • you're welcome. it's the only simple one that i know of, apart from an exclusive private method prefixing scheme: `- [MONObject doSmth_PRIVATE_MONObject` -- that could be used to reserve a private method, but it would not stop others from accessing/calling the method via introspection/runtime/nm peeking. – justin Apr 25 '12 at 20:34
1

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.

Lvsti
  • 1,525
  • 15
  • 15
0

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.

Colin Wheeler
  • 3,343
  • 2
  • 21
  • 23
-1

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
edc1591
  • 10,146
  • 6
  • 40
  • 63
Jonathan Naguin
  • 14,526
  • 6
  • 46
  • 75
  • That is simply wrong for this question. He knows that, but you can send a method never declared or declared in .m messages. Look at the question, he did it. Your approach only hides the declaration if the .m is imported. – Binarian Aug 29 '13 at 17:09