1

This is what I have in my implementation file for one of my classes...

Code Setup #1

@interface MyViewController (PrivateMethods)
- (NSString *)myPrivateMethod;
@end

@implementation MyViewController
- (void)viewDidLoad
{
    NSString *myString = [self myPrivateMethod];
    NSLog(@"%@", myString);
}

- (NSString *)myPrivateMethod
{
    return @"someString";
}
@end

With this code, everything works and it logs "someString".

But shouldn't my code look differently somehow? I actually am using that category by accident (I had copy/pasted something and didn't notice "PrivateMethods" was there; I meant to be using a class extension).

Shouldn't my code actually look like one of the following:

Code Setup #2

@interface MyViewController ()
- (NSString *)myPrivateMethod;
@end

@implementation MyViewController
....

Or:

Code Setup #3

@interface MyViewController (PrivateMethods)
- (NSString *)myPrivateMethod;
@end

@implementation MyViewController (PrivateMethods)
....

What are the nuances behind what is happening in this situation? How is Code Setup #1 different from Code Setup #2?

Edit: Question about Setup #3

What does setting it up like this accomplish? Would this even "work"?

@interface MyViewController (PrivateMethods)
- (NSString *)myPrivateMethod;
@end

@implementation MyViewController
- (void)viewDidLoad
{
    NSString *myString = [self myPrivateMethod];
    NSLog(@"%@", myString);
}
@end

@implementation MyViewController (PrivateMethods)
- (NSString *)myPrivateMethod
{
    return @"someString";
}
@end
MikeS
  • 3,891
  • 6
  • 35
  • 51

1 Answers1

2

the selectors just get pushed into the same flat namespace at runtime. the compiler adds no additional code to distinguish that the selector is a method defined in a category (when messaging) --it's all flat.

the categories' symbols are exported differently, but that does not really matter to the runtime once loaded.

you should generally use Setup #3: if a method is declared in a category, it should be defined in the category's @implementation. the compiler will save you occasionally and it is a purer structure. (of course, not every method belongs in a category). Similarly, the declarations in the @interface should be defined in the corresponding @implementation, and definitions of declarations in the class continuation (@interface MONClass ()) should also appear in the primary @implementation:

@implementation MONClass
// add your @interface MONClass definitions here
// also add your @interface MONClass () definitions here
@end

Updated Question

Yes, that would work fine. All you should need to do is #import the header which contains @interface MyViewController (PrivateMethods). I actually do this in some classes to categorize/organize by topic.

Typically, "Private Methods" are declared in the class continuation, but it is not necessary to do so (ivars/properties OTOH…).

justin
  • 104,054
  • 14
  • 179
  • 226
  • Updating my question with another question about Setup #3. Thanks so far though! – MikeS Sep 20 '12 at 18:48
  • 2
    I believe it's also significant in this case that (recent) Clang will treat an otherwise-undeclared method's definition as being a declaration for the same `@implementation` . – jscs Sep 20 '12 at 18:49
  • I am "sort of" aware of that Josh. Is that just with the new Xcode though or not? – MikeS Sep 20 '12 at 18:52
  • 1
    @MikeS: I'm not sure which compiler version it started with. It's been around for a few Xcode v's, though. At least since 4.2. – jscs Sep 20 '12 at 18:54
  • 1
    @JoshCaswell yes, good point (+1). clang now supports parsing of the entire `@implementation` scope. previously, this was possible, but the restriction was that the definition needed to precede use of the selector. since every `@implementation` block must be closed, it is a nice addition. – justin Sep 20 '12 at 19:05
  • to demonstrate, assuming neither selector is declared in an interface: `@implementation MONObject \n - (void)a { [self b]; /* << warning - b not declared */ } \n - (void)b { [self a]; /* OK - a is visible */ } \n @end` that *used to be* an issue, but clang is able to match the selector appropriately now. – justin Sep 20 '12 at 19:08
  • 1
    Oh, right, it's just that ordering isn't significant anymore. – jscs Sep 20 '12 at 19:13