iOS: Trying to call method implemented in category - objective-c

The prequel for this question is here.
I have a class (A) and the class has category. In the category I've defined and implemented a method.
Now I am trying in (let's assume B) class to call [a someMethod]. My B class can't reach this method. Isn't possible to call the category meths from some other class?

You didn't show your code, but in the .m file that refers to the category method, you do need to import the header of the file that defines the category interface.

If you define a category in a .m file, you will not be able to call the category's methods from outside of that .m file.

Unfortunately, you did not provide enough information about your problem. Thus, all we can do is tell you how it should be done, and guess about why you are having trouble.
When you post a question, you should post all the relevant information. In this case, that would be the code that does not work.
Also, your statement
My B class can't reach this method.
means almost nothing. You get a compiler error, a runtime error, the syntax window does not show it, what exactly do you mean by that?
Now, when you implement a category on a class, you want to declare the category in a header (.h) file...
#interface Foo (BarExtensions)
- (NSString*)bar;
#end
and then, in the implementation (.m) file, provide the implementation for those methods.
#implementation Foo (BarExtensions)
- (NSString*)bar {
return #"FooBar";
}
#end
Of course, you should name things appropriately.
Also, make sure you include the .m file in the list of files that get built for your target.
If you do that, there's not much left to go wrong.

Related

Objective-C : Accessing fields in implementation

Is it possible to fields defined only in implementation but not in interface definition ?
#interface MyInterface .... #end --> dict not defined here!!!
#implementation MyInterface
...
NSDictionary *dict;
...
#end
In this case if somewhere I somehow accessed to this class, can I access to the dict or should I create a getter just like in Java ?
Edit after #Rob's answer
Thanks for the answer Rob, I wish I have the implementation of these interface and classes. Instead I am trying to bind two different libraries ( I know it is reallllly bad as architectural point of view but this is where I end up).
Basically, I am in react-native world. And we are using react-native-video as our player layer. But since AVPlayer does not support some subtitle types our head company sent us a library that needs a player instance and a view instance to draw subtitle on the view. I believe they will bind to events of the player and draw sub titles based on player states.
So react-native-video is in this github repo with the interface and implementation.
I find the UIView that includes the properties and casted it to the object itself RTCVideo in this case). But now I am stuck. I can go and change some stuff as per your suggestion in the "Development Pods" to be able to access but this is my last bullet :) I prefer to convince these two libraries in a friendly way :)
Yes, but the above syntax isn't what you want. The modern way to do this is with a class extension.
Your header file is the same:
#interface MyInterface
#end
But in your .m file, you create an extension by appending ():
#interface MyInterface ()
#property (nonatomic, readwrite) NSDictionary *dict;
#end
Now, inside your .m file, you can access self.dict normally, but outside of your .m file it won't appear available.
For full details, see Programming with Objective-C: Class Extensions Extend the Internal Implementation.
The syntax you've written actually creates a static (global) variable called dict that isn't tied to any instance.
It is possible to create raw instance variables using a {...} syntax, either on the extension or on the implementation, but this isn't used that often today, except for managing raw buffers that you don't want accessors for. The syntax is either:
#interface MyInterface () {
NSDictionary *_dict;
}
...
#end
or on the implementation:
#implementation MyInterface {
NSDictionary *_dict;
}
...
#end
But I recommend simple extensions with properties any time you can. And if you are considering creating an accessor for it, you definitely want to use #property and let the system do it for you.
If I understand your edits correctly, you're trying to read the internal ivars of an object that doesn't expose them with an accessor, correct? I believe specifically you want to access _player.
There's several common ways to do that. The key feature you want is Key-Value Coding.
The simplest approach for this problem is -valueForKey:
AVPlayer *player = [view valueForKey:#"player"];
The first thing -valueForKey: looks for is _<key>, and if it's just an object pointer (as in this case), it just returns it.
(This can be broken if a class return false for +accessInstanceVariablesDirectly, but the default is true, and it's unusual to override this.)
Another very common approach is to just declare any methods you know exist as a category. (This won't work for _player, since it's not a method, but in case you need similar things.) Imagine you wanted to call the "private" method -removePlayerTimeObserver. In your .m file, just say you know about it using a category:
#interface RCTVideo (PrivateMethods)
- (void)removePlayerTimeObserver;
#end
And since you know about it, you can call it:
[video removePlayerTimeObserver];
If you're wrong, and that method doesn't really exist, then the program will crash. In Objective-C, almost all rules are advisory. You can break them if you want to. ObjC programmers tend to be big rule-followers because otherwise the program crashes and ObjC has very clear rules that are pretty easy to follow. It's not because the system forces us to.

When do you create initialization methods in .m files using class extension?

I was going through one of Apple's tutorial (your second iOS app). Basically, you have a primary data class and a data controller class. Controller class manipulates the primary data objects by creating an array that holds them.
Suddenly this pops up:
"...But the “create the master collection” task is a task that only the data controller object needs to know about. Because this method does not need to be exposed to other objects, you do not need to declare it in the header file."
And turns out the initialization of the "master collection" appears in the .m file as a class extension instead of the header file. Why do we want to do this? What's wrong with declaring the method of initialization within the header file directly?
Header file of the data controller:
#import <Foundation/Foundation.h>
#class BirdSighting;
#interface BirdsSightingDataController : NSObject
#property (nonatomic, copy) NSMutableArray *masterBirdSightingList;
- (NSUInteger)countOfList;
- (BirdSighting *)objectInListAtIndex:(NSUInteger)theIndex;
- (void)addBirdSightingWithName:(NSString *)inputBirdName location:(NSString *)inputLocation;
#end
this is the corresponding .m file:
#import "BirdsSightingDataController.h"
#import "BirdSighting.h"
#interface BirdsSightingDataController ()
- (void)initializeDefaultDataList; //class extension
#end
#implementation BirdsSightingDataController
...
Putting methods in an interface inside of a .m file is the proper way of making methods hidden.
-
There's nothing really "wrong" with declaring this method in the header file. You can do this if you want.
However, it's better practice to hide methods in your implementation file by using private header extensions if there's no need to make the method public. This means that if no other class needs to call this method, or if no other programmer needs to call this method, then it's better practice to keep the method private, or hidden.
A case like this will help explain the situation:
First, putting methods in a hidden interface extension in your .m files is a conscious decision. As another developer, if I am looking at your code and see that you have consciously decided to put a method in a hidden interface () in your implementation file, I will know that this method is used only in this class... and that YOU have done this on purpose.
Furthermore, it is good practice because if you are developing an API which is going to be used by other people, or working on the same code base with other developers, it limits their ability to call specific methods outside of the class itself. That means, they can't accidentally call the method from another object.

Purpose of Obj-c categories in a specific situation.

I'm quite new at Objective-C and i've a question :
I've been through some Apple's sample code and found the following :
https://developer.apple.com/library/ios/#samplecode/GLSprite/Listings/Classes_EAGLView_m.html#//apple_ref/doc/uid/DTS40007325-Classes_EAGLView_m-DontLinkElementID_4
In the top of the file, I found to uses of Objective-C categories
#interface EAGLView (EAGLViewPrivate)
- (BOOL)createFramebuffer;
- (void)destroyFramebuffer;
#end
#interface EAGLView (EAGLViewSprite)
- (void)setupView;
#end
Just after that, starts the implementation of the EAGLView class.
What is the real purpose of categories here, as the 3 functions above could also be defined directly in the header file ??
Thx
As indicated by the first category's name ("EAGLViewPrivate") declaring these methods in the .m file is a way of simulating private methods. Objective-C doesn't have true support for private methods, but since these aren't declared in the .h file, the compiler will warn when code outside the .m file where they're declared tries to call them.
This is more commonly done with class extensions (a special case of a category) these days, mostly because using a class extension results in the compiler warning if a "private" method isn't implemented in the class's #implementation block. Class extensions were a new feature in Objective-C 2.0, so in older code, you'd often see a category with private in the name as in the code you've posted. The intent is the same.

Objective C shenanigans

In my quest to be the grandmaster of Objective C, I keep running into it's subtleties, which I want to share with ya'll and gain an understanding why
1) I have two init methods, the one that is inherited by NSObject for my Objective C class and one is a custom method that I create off my own, let's say
initCustomMethod:(int)par1 argument2:(int)par2;
My Aim is to call initCustomMethod through the provided init method, essentially
-(id)init{
return [self initCustomMethod:1 argument2:3];
}
Naturally, maintaining the order, I have init appearing before initCustomMethod in the .m file. Xcode warns me telling me that the initCustomMethod is not found, I go ahead and shuffle the order and have init appearing after initCustomMethod is declared and there is no such warning message anymore and everything is fine.
I concur that the order is important since it's essentially derived from C, however I am not sure of this. Because, i shuffled the order of some properties and their custom methods, with the properties #synthesize being declared after the custom setter method for a given property, but there was no such error replica.
Can anyone point out the malice here?
Thanks guys!!!
Very cool guys, thanks for helping me out with this. Also, since I have a custom init method, I am initializing the super in this method and using the original init method to call the custom init method.
Anything wrong with this?
Before you reference it anywhere, you should declare initCustomMethod:argument2 in your interface, which would usually be in your header file.
For example, you would usually have a .h file that looks like:
#interface MyClass
{
//instance variables
int anInstanceVariable;
}
// properties
#property (nonatomic, assign) int aProperty;
// methods
-(id)initCustomMethod:(int)par1 argument2:(int)par2;
#end
And if you did this, the order in which you define init and initCustomMethod:argument2: won't matter. This is because the declaration tells the compiler that you are going to define the method, and what it will look like, so it isn't confused when you use it later.
It's a bad idea in Objective-C to use a function or a method before it is either declared or defined. Putting initCustomMethod:argument2: before init means that the former is already defined in the latter. But if you'd just declare it in the header, it wouldn't matter which order they went in.
Add your custom method name in your header file - the compiler just goes through things in order. If you don't have a forward declaration, the compiler won't know what to do with that call. You're going to need to put it in the header if you want other parts of your program to be able to call it anyway.

Can a class use methods declared in one of its categories?

I have a big class. To sum up, it has only one method that other classes should call and then a bunch of methods to do different stuff, depending on the type of data received. The .m file is getting so large that I want to split it up. My idea is to divide the methods among different categories (each category will work with a specific type of data). And so I did.
Inside of the main method I didn't change anything, so lines such as
[self methodNowInMyCategory];
are still there. However, I now get warnings in my class's main file since "instance method -methodNowInMyCatefory not found". The main .h file is importing the .h files of the categories, so the methods are visible (Xcode colors the code). The class just does not recognize them as its own.
Is there a way to, in a class, use a method declared in one of its categories? If not, which approach would you recommend me to solve my problem? The main method receives a file path, opens the file, analyzes the content and then sends it one or more methods.
You can split your category declarations into one or more .h files, and then import the category headers in your class's main .m.