Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 ...

like image 601
LuisEspinoza Avatar asked May 02 '13 17:05

LuisEspinoza


1 Answers

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

like image 102
Sulthan Avatar answered Sep 30 '22 00:09

Sulthan