LuisEspinoza
LuisEspinoza

Reputation: 8538

How to use an internal method in a Objective-C category?

Trying to extend the capabilities from a open source project, I wrote a category for add a new method. In this new method, the category needs to access to an internal method from the original class, but the compiler says that it can't find the method (of course, is internal). Is there any way to expose this method for the category?

EDIT

I don't want to modify the original code, so I don't want to declare the internal method in the original class header file.

The code

In the original class implementation file (.m), I have this method implementation:

+(NSDictionary*) storeKitItems
{
  return [NSDictionary dictionaryWithContentsOfFile:
          [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:
           @"MKStoreKitConfigs.plist"]];
} 

In the category, I want to add this method:

- (void)requestProductData:(NSArray *(^)())loadIdentifierBlock
{
    NSMutableArray *productsArray = [NSMutableArray array];
    NSArray *consumables = [[[MKStoreManager storeKitItems] objectForKey:@"Consumables"] allKeys];
    NSArray *nonConsumables = [[MKStoreManager storeKitItems] objectForKey:@"Non-Consumables"];
    NSArray *subscriptions = [[[MKStoreManager storeKitItems] objectForKey:@"Subscriptions"] allKeys];
    if(loadIdentifierBlock != nil) [productsArray addObjectsFromArray:loadIdentifierBlock()];
    [productsArray addObjectsFromArray:consumables];
    [productsArray addObjectsFromArray:nonConsumables];
    [productsArray addObjectsFromArray:subscriptions];
    self.productsRequest.delegate = self;
    [self.productsRequest start];
}

In every line in which I call storeKitItemscompiler says: Class method "+storeKitItems" not found ...

Upvotes: 5

Views: 7021

Answers (3)

Nathan Day
Nathan Day

Reputation: 6037

In you category implementation file you can define and informal protocol for the method

@interface YourClasses (ExternalMethods)

+(NSDictionary*) storeKitItems;

@end

This will stop the compiler from complaining about not knowing of the method storeKitItems in you category.

Upvotes: 0

Sulthan
Sulthan

Reputation: 130172

This is trivial, make a forward declaration of the method.

Unfortunately, in obj-c, every method declaration must be inside @interface, so you can make it work in your category .m file with another internal category, e.g.

@interface MKStoreManager (CategoryInternal)
   + (NSDictionary*)storeKitItems;
@end

No implementation is needed, this only tells the compiler the method is somewhere else, similarly to @dynamic with properties.

If you are only interested in removing the warning, you can also just cast the class to id, the following should work, too:

NSDictionary* dictionary = [(id) [MKStoreManager class] storeKitItems];

However, my favorite solution is to do it a bit differently, let's assume the following example:

@interface MyClass
@end

@implementation MyClass

-(void)internalMethod {
}

@end

@interface MyClass (SomeFunctionality)
@end

@implementation MyClass (SomeFunctionality)

-(void)someMethod {
  //WARNING HERE!
  [self internalMethod];
}

@end

My solution is to split the class into two parts:

@interface MyClass
@end

@implementation MyClass
@end

@interface MyClass (Internal)

-(void)internalMethod;

@end

@implementation MyClass (Internal)

-(void)internalMethod {
}

@end

And include MyClass+Internal.h from both MyClass.m and MyClass+SomeFunctionality.m

Upvotes: 5

rmaddy
rmaddy

Reputation: 318934

A category has no access to the private methods of a class. It's no different than trying to call those methods from any other class. At least if you call the private method directly. Since Objective-C is so dynamic, you can call private methods (which is a bad idea) using other means such as using performSelector or with NSInvocation.

Again, this is a bad idea. An update to the implementation of the class could break your category.

Edit: Now that there is code posted -

Since the +storeKitItems method is not declared in the .h file, no category or other class can access the private method.

Upvotes: 1

Related Questions