I am trying to create a global function or method in objectiveC. This is so that I can call it from any of my view controllers.
I already checked out this post: How to create global functions in Objective-C
So what I did was in Xcode 6 I created new file and choose a category drop down. that created these two *.h & *.m files for me. I added my method called SaveWeatherDataNow in it
//NSObject+SaveWeatherData.h
#import <Foundation/Foundation.h>
#interface NSObject (SaveWeatherData)
+(void)SaveWeatherDataNow:(NSString *)XML;
#end
//NSObject+SaveWeatherData.m
#import "NSObject+SaveWeatherData.h"
#implementation NSObject (SaveWeatherData)
+(void)SaveWeatherDataNow:(NSString *)XML
{
NSLog(#"SaveWeatherDataNow XML lenght: %ld", [XML length]);
}
#end
Now in my another view controller if I call this method then complier doesn't find it at all. What did I miss?
// v1CitiesAdd.m
#import "NSObject+SaveWeatherData.h"
#implementation v1CitiesAdd
...
...
-(IBAction) doneAction
{
...
[SaveWeatherData SaveWeatherDataNow:XML]; // Complier Error: Use of undeclared identifier SaveWeatherData
Change the + to a - (in front of (void)):
-(void)SaveWeatherDataNow:(NSString *)XML;
That way, you can refer to the method within your SaveWeatherData object.
Don't forget to change it in both the header (.h) file as well as the class (.m) file.
You could also call
[NSObject SaveWeatherDataNow:XML];
by leaving the +.
===
When you use a +, it's a class method. It works globally, and doesn't know or care about individual objects.
When you use a -, it's an object method. It works within a specific object.
So, if there is a Brick class,
+(void) smash;
would change/update every brick to be smashed.
-(void) shatter;
would shatter a specific brick you send that message to.
[myBrick1 shatter]; would only shatter the one brick.
[Brick smash]; would change something globally for all bricks.
I am writing a different answer, because I think the best answer to this question would be Don't do it!.
To create a category for NSObject to save data is a very ugly thing to do.
WHY
It would mean that when you import it to a class EVERY class that inherits from NSObject (almost all of them) would suddenly have that extra method.
For example, code like this would work:
NSNumber *myInt = #(3)
NSString *myXmlAsString = [NSString stringWithFormat:#"<rating>%#</rating>",myInt.integerValue];
If you keep using the static method (with +) you could do:
[NSObject SaveWeatherDataNow:myXmlAsString];
or
[NSNumber SaveWeatherDataNow:myXmlAsString];
or even
[UIImage SaveWeatherDataNow:myXmlAsString];
If you change it to an instance method (with -), you could do:
[myXmlAsString SaveWeatherDataNow:myXmlAsString];
or
[myInt SaveWeatherDataNow:myXmlAsString];
or use most of the existing variables in that scope, which would seem very strange to say the least.
WHAT YOU SHOUD DO INSTEAD
I would use one of following 2 options:
Create a class that manages data saving/loading for you. The usage should then look like this:
[DataManager saveWeatherDataNow:myXmlAsString];
If you don't need that much, only that function, you could create a Utility class and add that static method (in case you do not have one already).
[Utility saveWeatherDataNow:myXmlAsString];
PS: by convention, you usually start method names with lowercase.
[SaveWeatherData SaveWeatherDataNow:XML]; // Complier Error: Use of undeclared identifier SaveWeatherData
The root of the problem here is that you haven't defined a class named SaveWeatherData. Instead, you've created a category on NSObject, so that you can call +SaveWeatherDataNow: on any class that's derived from NSObject. The straightforward solution is to create a class instead of a category. Change these lines:
#interface NSObject (SaveWeatherData)
#implementation NSObject (SaveWeatherData)
to these:
#interface SaveWeatherData
#implementation SaveWeatherData
and that should allow a call like this:
[SaveWeatherData SaveWeatherDataNow:XML];
to work correctly.
Related
This is header file/Interface file(className.h).
Here printSomething method is declared as an extension. And I'll call it later in main.m
extension.h
#import <Foundation/Foundation.h>
#interface extension_class : NSObject
#end
#interface extension_class () // This is the external method which is added using extension
- (void) printSomething;
#end
This is the Implementation file(className.m). Here printSomething method is defined.
extension.m
#import "extensions.h"
#implementation extension_class
- (void) printSomething
{
NSLog(#"I'm the method defined inside extension class but declared by using extensions");
}
#end
So far everything works fine. Now My question is simple why can't I access that printSomething method if I declare(until now declaration and definition was not done in same file) it in implementation file. As in the below code snippet? (Please compare and observe the changes among above two .h and .m files with below ones to get my point)
extension.h
#import <Foundation/Foundation.h>
#interface extension_class : NSObject
#end
extension.m
#import "extensions.h"
#interface extension_class () // This is the external method which is added using extension
- (void) printSomething;
#end
#implementation extension_class
- (void) printSomething
{
NSLog(#"I'm the method defined inside extension class but declared by using extensions");
}
#end
This is main method which is common in both cases.
main.m
#import "extensions.h"
int main()
{
#autoreleasepool
{
extension_class *object = [[extension_class alloc]init];
[object printSomething];
}
return 'O';
}
So what is point in having extensions in objective C if it doesn't allow us to add methods anywhere we like? or Is there any other method to achieve what I said above?
You're free to define extensions in the .m file. This is incredibly common. Those extensions won't generally be known to importers of the .h file, so they won't easily be callable from other files. That's a good thing. It lets us make "private" extensions, which is very useful and common.
They're not really private. Anything can call anything in ObjC. Outside callers just won't know about the method. But they can declare the method themselves as a category (note the text inside the parentheses) and call it:
OtherClass.m
#import "ExtensionClass.h"
#interface ExtensionClass (ThingsIKnowYouHave)
- (void) printSomething;
#end
...
[extensionClass printSomething];
Or they could of course just call it directly without declaring it (though this can cause ARC problems, so avoid this in modern ObjC):
[(id)extensionClass printSomething];
Or they could call it as a selector (again, this can cause ARC problems; so using the category is best):
[extensionClass performSelector: NSSelectorFromString(#"printSomething")];
There's really not much point to creating extensions in the header file (i.e. "public" extensions). If it's in the header file, you might as well just put it in the interface. The most common use of extensions (basically why they were invented), is so you can define methods inside the implementation file.
Extensions shouldn't be confused with categories, where there is text inside the parentheses. These were created to help organize large classes, and later were used for "informal protocols" before #optional was added. Extensions can add methods directly to the base class. Category interfaces just say "this method might exist." Extension interfaces are formal continuations of the primary interface (the compiler requires that they be implemented).
For more on categories and extensions, see Customizing Existing Classes in the Programming with Objective-C guide. See also Defining Classes in the same guide, which may clear up some confusion I believe you have about header files and interfaces.
Imagine I have define a class MyClass as follows:
The class interface file:
#import <Foundation/Foundation.h>
#interface MyClass : NSObject
#property (nonatomic) NSString *myProperty;
- (void)myPublicMethod;
#end
The class implementation file using categories:
#import "MyClass.h"
#interface MyClass (MyCategory)
- (void)myPrivateMethod;
#end
#implementation MyClass
- (void)myPublicMethod {
NSLog(#"myPublicMethod was called!");
[self myPrivateMethod];
}
- (void)myPrivateMethod {
NSLog(#"myPrivateMethod was called!");
}
#end
An alternative class implementation file NOT using categories:
#import "MyClass.h"
# implementation MyClass
- (void)myPublicMethod {
NSLog(#"myPublicMethod was called!");
[self myPrivateMethod];
}
- (void)myPrivateMethod {
NSLog(#"myPrivateMethod was called!");
}
#end
Was hoping someone could explain the difference between the two implementation file approaches.
Is it the case that using categories means the "private" methods are inherited by any subclasses of MyClass and not using categories means the "private" methods are not inherited by any subclasses?
All methods that exist on a class are always inherited and are callable by anyone regardless of how you declare them. The main difference is whether anybody knows about them. There was also a historic need to declare things before use which leads to internal forward declarations in older and old-style code.
A category is used to add methods to an existing class. A common use is to extend the functionality of one of the existing classes. For example you might implement:
#interface NSURL (HTTPQueryParameters)
- (NSDictionary *)httpQueryParameters;
#end
So from then on you've given NSURL itself the knowledge required to parse HTTP protocol query parameters. It's often the correct factoring to add functionality directly to classes you don't have the source for.
Objective-C used to follow the C rule that methods had knowledge only of those methods that had preceded them within the compilation unit. So to be able to call a method that appeared later in the source file you'd need a forward declaration. If you didn't want to publish that method for the world to see you could achieve that with a category or a class extension (which for this purpose is just an unnamed category).
Nowadays Objective-C methods can call any method that is defined anywhere within the compilation unit, including subsequently in the same source file. It's therefore now normal not to collect up your unpublished methods into a category or an extension just for the benefit of the compiler.
That leaves categories for:
adding functionality to existing classes; and
segmenting your classes if they become very large;
Class extensions are now primarily for:
declaring #propertys without publishing them.
In Objective-C any method call can be sent to any object — objects are dynamically typed. So there's a mapping table in memory at runtime for every class from method name to implementation. The lookup process is to see whether the method is implemented in the class dispatched to. If not then dispatch to the superclass. An exception will be raised if the runtime runs out of superclasses.
The declaration of the method in a category #interface only serves to expose the method to users of the class, including -- as you mentioned in your comment -- subclasses.
(It would be much more usual to use a class extension (sometimes called an "anonymous category") declare a method that you're defining in the main implementation block. Actually, I'm not 100% sure what the interaction is between your category declaration and the main block definition -- I wouldn't have been surprised if it didn't compile, but it does.)
Thus, the only difference between your two examples is that the declaration allows you to create a private header in a situation where you want your own subclasses to access this method, but have framework users who you want to restrict.
My question is, that I would know how to use 2 .m files for one objectclass also for one header (.h)
I have a big method with 20000+ lines and I would, that this method stand alone in a .m file and the other methods in the other .m file. I have done it, but I get errors, that the methods aren not in the one .m file. I get a link error, but i can remove the link error if i delete the second .m file.
Is it possible to create 2 .m files for one header ?
If yes pleas tell me how?
I have a big method with 20000+ lines
Okay, that's your problem right there. That's what you need to fix. Splitting things up into two implementation files is a distraction. This is your main problem. There's virtually no circumstances where this is not a terrible way of doing things.
Methods should be a few dozen lines long at most. If you find yourself writing a method that is longer than that, you need to break the functionality down into smaller pieces. Create smaller methods to do part of the job, then call those methods from your original method.
Classes should not be this size. If you are creating a file with more than a couple of thousand lines of code in, it's a huge warning sign that one class is responsible for too much functionality. You should break the functionality down into several classes, each of which is responsible for one key piece of functionality.
I get a link error
If you post a sentence like this to Stack Overflow, it should be accompanied by the actual error you get.
You can make the excessively long method a category of the class:
MyClass.h:
#interface MyClass
#property ...
-(void) method;
...
#end
#interface MyClass (BigMethod)
-(void) bigMethod;
#end
MyClass.m:
#implementation MyClass
-(void) method
{
...
}
...
#end
BigMethod.m
#implementation MyClass (BigMethod)
-(void) bigMethod
{
...
}
#end
However, a 20k line method is absurd. You should really refactor it.
You have several approaches:
you could split your methods into 2 different categories:
//-- MyClass1.m
#implementation MyClass (part1)
#end
//-- MyClass2.m
#implementation MyClass (part2)
#end
I defined 2 categories for symmetry reason; of course you also need a "base" #implementation of your class (i.e., without the category specifier); you can choose whether you define a "base" and and extension category, or "base" and two categories, etc...
or you might try including the second .m file inside of the first one:
//-- MyClass1.m
#implementation MyClass
<first part>
#include "MyClass2.m"
#end
Both should work.
Let alone the possibility of refactoring your class, which would be the best option.
I have created an NSObject subclass without any implementation and named it "WebView".
In my code I need to be able to dynamicly instantiate objects of this class using NSClassFromString.
While it seams like a trivial work, I am having problems with this specific class name "WebView".
It seams like NSClassFromString() is failing for this specific class name, but with lldb I can print both class1 and class2 descriptions and for both it says "WebView".
Anyone else experiencing same issue? Is there some list of forbidden class name like it is for instance variables etc?
#interface WebView : NSObject
#end
#implementation WebView
#end
#implementation ViewController
- viewDidLoad {
Class class1 = [WebView class];
Class class2 = NSClassFromString(NSStringFromClass(class1));
NSAssert(class1 == class2, #"Classes not equal"); // FAIL
}
#end
And another example:
[class1 new]; // OK
[class2 new]; // EXC_BAD_ACCESS (code=2, address=0x0)
When I try to allocate the WebView. It looks into apple's internal framework as shown in image.
You should always use a three letter prefix for your classes to avoid conflicts like this. Apple reserves all two letter prefixes for itself.
When creating your project in Xcode, it will even ask you what prefix you would like to use and it will create new classes using that prefix for you.
WebView is the instance apple sdk class. When i used UIWebView i was seen webView class how ancestor UIWebView. So, do not use class with name WebView, this name use the apple.
I'm stuck on this problem, please help me.
I have a ViewController with class name: FLViewController. In the .m file, I declare some other interfaces:
#interface FLViewController (InternalMethods)
- (void)updateButtonStates;
#end
#interface FLViewController (AVCaptureManagerDelegate) <AVCaptureManagerDelegate>
-(void)adMobProcess
#end
In the implementation of FLViewController, I call method adMobProcess of Interface FLViewController (AVCaptureManagerDelegate) but the compiler said that "No visible #interface for FLViewController declares selector adMobProcess"
I can move the method above into the implementation of FLViewCOntroller (currently it is placed in the category AVCaptureManagerDelegate) however, I want to know how to call the method in another category.
By declaring your categories inside the .m file (which limits their scope to that one file), you've effectively declared some private methods for FLViewController. If this is what you want, you don't need categories.
Categories in Objective-C are meant to be reused. So you want to declare your categories in a header file (or files), and include those headers in any .m file where you use them.
Finally I found the cause. I didn't declare method signature in the Category, just only the method implementation in the Category implementation block.I declared the method and it works.