0

I have a singleton class that is instantiated as follows:

#import "FavoritesManager.h"

static FavoritesManager *sharedFavoritesManager = nil;

@implementation FavoritesManager

+ (id)sharedManager {
    @synchronized(self) {
        if (sharedFavoritesManager == nil) {
            sharedFavoritesManager = [[self alloc] init];
        }
    }

    return self;
}

This returns an object, but for some reason it will only respond to class methods. If I call a instance method I get

+[FavoritesManager testMethod]: unrecognized selector sent to class 0x59198

For what it's worth, this is what testMethod looks like:

- (void)testMethod {
    NSLog(@"Test");
}

and I'm absolutely positive it's declared in the interface. I've used this exact code in other classes and it works like a charm, so I don't really understand what the problem is here. One thing that is suspicious is the plus sign in +[FavoritesManager testMethod], but I can't explain it. Any ideas?

EDIT: I was confusing public/private and class/method terminology. Thanks to everyone who pointed that out.

serverpunk
  • 10,665
  • 15
  • 61
  • 95

7 Answers7

6

If you want to call testMethod from another class method then you need:

+ (void)testMethod {
    NSLog(@"Test");
}

The reason is that if you call a class method then there's no instance, so nothing on which to call instance methods. But probably you want to call:

[[FavoritesManager sharedManager] testMethod];

Which means 'get the shared instance, then call testMethod on it'. Thinking as I type, you might also like to add:

+ (void)forwardInvocation:(NSInvocation *)anInvocation
{
    id sharedManager = [self sharedManager];

    if ([sharedManager respondsToSelector:
            [anInvocation selector]])
        [anInvocation invokeWithTarget:sharedManager];
    else
        [super forwardInvocation:anInvocation];
}

Which is the Objective-C means for message forwarding. So if the metaclass FavoritesManager receives a message it can't respond to, it lets its shared manager instance have a go. That means that:

[FavoritesManager testMethod];

Becomes functionally equivalent to (though a little slower than):

[[FavoritesManager sharedManager] testMethod];

Providing that you haven't implemented a class method in addition to an instance method. You can learn more about message forwarding in Apple's official documentation.

Tommy
  • 99,986
  • 12
  • 185
  • 204
4

The error indicates that you're sending the message testMethod to the class, rather than an instance.

The reason for this is that your sharedManager method is incorrect. You are currently returning self, which, in this class method, is the class itself. This means that when you write [[FavoritesManager sharedManger] testMethod] you end up sending testMethod to the class. Since testMethod isn't a class method, you get an error.

You should have return sharedFavoritesManager; at the end of sharedManager, not return self;. The latter is correct only in instance method initializers.

Also, as dbrajkovic commented, you seem to be confused about public/private and class/instance methods. Strictly, ObjC has no private methods. You can hide the declaration, which will cause a compiler warning, but the message will still be sent and the method will be called. The + and - distinguish class methods from instance methods; the distinction is which kind of object you send a message to. Info here: What is the difference between class and instance methods?

Community
  • 1
  • 1
jscs
  • 63,694
  • 13
  • 151
  • 195
2

The error is right you must be calling [FavoritesManager testMethod] which means you're trying to call a class method. I believe you want [[FavoritesManager sharedManager] testMethod];

dbrajkovic
  • 3,693
  • 1
  • 17
  • 14
1

+ at the start of a method declaration means that it's a class method, - means that it's an instance method. Do this:

+(void)testMethod {
    NSLog(@"Test");
}

If you want to invoke testMethod on your sharedManager, then keep the testMethod declaration as you have it and instead change your invocation to

[[FavoritesManager sharedFavoritesManager] testMethod];

Either will work, and choosing between the two is a matter of app design.

QED
  • 9,803
  • 7
  • 50
  • 87
1

Instead try

[[FavoritesManager sharedFavoritesManager] testMethod];
SuperRod
  • 557
  • 3
  • 8
0

there are no priavte methods in obj-c. But anyway on a singleton you are always calling from the outside of the class, so only declare "public methods". for detailed help post your code.

calimarkus
  • 9,955
  • 2
  • 28
  • 48
0

Call your singleton instance:

[[ FavoritesManager sharedManager] testMethod];

peterept
  • 4,407
  • 23
  • 32