In Objective-C, when should I use class methods and when should I use instance methods? - iphone

What is the difference between class and instance methods in Objective-C and when should I use each of them?

Using the tired old Car analogy...
Think of a Class like it is a factory that makes Instances of the class. For example, you might have a Car class and you might declare a method like:
+ carWithColor: (NSColor *) aColor;
And that method would then create a new Car instance, set the color, and return it:
+ carWithColor: (NSColor *) aColor
{
Car *aCar = [[[self alloc] init] autorelease];
[aCar paintWithColor: aColor];
return aCar;
}
Now, that Car class would then declare an instance method that allows the car to be painted. Why an instance method? Because every car can have a different color (and the color of the car would likely be stored in an instance variable).
- (void) paintWithColor: (NSColor *) aColor
{
... do your paint stuff here ...
}
This is explained in the Objects, Classes, and Messaging section of the Objective-C documentation.

This is an old post, but since it comes up first in a Google search I thought I'd add to it.
I'm not going to talk about class methods used as factory methods. I'd like to talk about their use in utility methods. You can/should use class methods for utility methods that are independent of state. What does this mean? Well, for instance, if you're formatting a date the same way for all instances, that's a utility method that should be a class method. Think of the utility method like a screw driver. You don't need to make a new instance of the screw driver every time you want to do something with it. The screw driver remains constant. So, for instance, I have a class that includes a private method that generates a string of emDashes used for displaying to the view. This method is not dependent on state and hence will not vary by instance. Think of class utility methods like constants.
+ (NSString *)emDashString {
return #" \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014";
}
You can call this method generically within the class (it's private in my example) like this:
NSString *string = [[self class] emDashString ];
I've deliberately chosen a bit of a trivial example to drive the point home. You would only bother making this a class utility method if you're going to need this string more than once in your class. Notice that instead of referring to the class by name I call it generically with [self class] since this is called internally. If it's exposed and you want to call it from another class then refer to it by the class name as usual.

Instance methods do things with instances of a class:
NSString *myString;
myString = [[[NSString alloc] initWithString:#"Hello, world."] autorelease];
NSLog (#"myString's length: %u", [myString length]); // instance method
Class methods can do class-specific things without relying on an object instance, often returning an instance of the class, or some other class-specific result:
NSLog (#"%#", [NSString stringWithString:#"Hello, world."]); // class method
I think it may be rare to see class methods that do not return something.

You don't need to implement both. Either option is available to you as you design your class.
An instance method can operate on an instance of the class. This can get or set a property, or cause behavior you only want that instance to perform. You need to actually have an instance to use it. These can either use or change the state of the instance.
// Notional instance methods
myHouse.color = blueColor;
[myCar accelerate];
speed = myCar.speed;
A class method operates on the notion that the class exists. It can be used to create an instance, or perform a calculation that doesn't depend on having an instance. You might have a class for custom math helper, that essentially contains functions.
// Notional class method uses
myString = [NSString stringWithFormat:#"&f", floatToConvert];
myResult = [MyMathHelper MyFunctionWithInput:myInput];

Class method signatures are prefixed with +, instance methods with - so in your header file declarations would look something like this:
-(void)setAllThings:(NSArray*)things; //instance method
+(void)setAllClassThings:(NSArray*)things; //class method
And of course the same rules apply when you define the methods in the .m file.

Related

turn away to assign a property from Class method

I am just curious as if there is anyway to assign a property that is being triggered from class method?
Ex:
+ (void)asyncResponse:(NSDictionary*)response:(NSError*)error
I am getting a response of NSURLConnection in that call, however, I am trying to use this in my another class and set that dictionary as a property, but it gives me the error as this is a class method. That asyncResponse is a "Delegate call" I am using to direct to any particular class in runtime.
Thanks.
There are lot of options you may use to store the variable. Why do you need a property in class method. Class method is run when there is no role of instance. But, of course you, could pass create an instance of the class in the class method and store the value in the object. Other way would be to create some global variables and assign the values to it such that it can be accessed through out the class.
Creating instance to store the variable into property;
+ (void)asyncResponse:(NSDictionary*)response:(NSError*)error{
MyClass *me = [[MyClass alloc] init];
me.someProperty = response;
}
But, I dont think you were looking for this, because it is very simple use of the class and properties.
The other thing you could do is create some static variables inside your implementation and then access those variables through your class. You could even create your own custom getter and setter for it, for more easy uses.
#interface MyClass:NSObject
+(void)setResponse:(NSDictionary*)response;
+(NSDictionary*)response;
#end
NSDictionary *globalResponse;
#implementation MyClass
+(void)setResponse:(NSDictionary*)response{
if(response != globalResponse){
globalResponse = response;
}
}
+(NSDictionary*)response{
return globalResponse;
}
You could set the default value for the response in initialize or load method. This makes a simple class level property.

Objective-C singleton only responds to class methods

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.
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.
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?
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];
+ 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.
Instead try
[[FavoritesManager sharedFavoritesManager] testMethod];
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.
Call your singleton instance:
[[ FavoritesManager sharedManager] testMethod];

objective-c static/class method definition - what is the difference between "static" and "+"?

I'm wondering if someone can explain the difference between the functions below. They are both static, but require different signature syntaxes. I'm wondering how these are handled at runtime, and why you would use one over the other?
+ (int) returnInt:(NSString *)myString1 withString2:(NSString *)myString2
{
if ([myString1 isEqualToString:myString2])
return 1;
else
return 0;
}
vs.
static int returnInt(NSString *myString1, NSString *myString2)
{
if ([myString1 isEqualToString:myString2])
return 1;
else
return 0;
}
Thanks!
Unlike in (say) C++, where static member functions are just ordinary functions in the class' namespace, Objective-C has proper class methods.
Since classes are objects, calling a class method is really like calling an instance method on the class. The main consequences of this are:
1) Calling a class method incurs a slight (although generally inconsequential) overhead, since method calls are resolved at runtime.
2) Class methods have an implicit 'self' argument, just like instance methods. In their case, 'self' is a pointer to the class object.
3) Class methods are inherited by subclasses.
together, 2 and 3 mean that you can do stuff like this with a class method:
+ (id) instance
{
return [[[self alloc] init] autorelease];
}
then create a new class that inherits the method and returns a new instance of itself, rather than the superclass.
I believe that marking an ordinary c function static will just make it unavailable to files other than the one it's defined in. You'd generally do this if you wanted to make a helper function that is only relevant to one class and you wanted to avoid polluting the global namespace.

How to call a method without an instantiated object

This is an objective-c question.
I would like to call a method in an object, but there is no instantiation of the object. Is this possible?
The method I want to call is not a class method.
You can't call a method on an object that doesn't exist. But you can call a method on a class even if you have no instantiated objects of that class. (That's what alloc is in #fbrereton's answer -- a class method).
Class methods are declared and defined with a + instead of a -, are called on the class rather than the instance, and cannot access self or any instance variables in the class (for reasons that should be obvious).
Unless the method is static you will not be able to do this. static routines in Objective-C will be prepended with a +. For example NSObject provides these two routines (among many):
+ (id)alloc; // static - an NSObject instance is not required
- (NSString*)description; // nonstatic - an NSObject instance is required
One would make the respective calls like so:
NSObject* result = [NSObject alloc];
NSString* desc = [result description];
Sorry to nit-pick Chris' terminology, but we don't call a method on an object in Objective-C, we send a message to an object. When you send a message, the runtime will look up the appropriate method and call it. The distinction matters.
Perhaps you just want a plain-old C function. If you don't want a class method, and you don't want an instance method, that appears to be your only option. Don't be afraid of using C functions in Objective-C. Every technique has its place.
You can indeed invoke an instance method without an instance, provided it is functionally a class method (that is, it accesses no instance variables). Here's an example:
/*
Compile with:
gcc -framework Foundation inst_method_without_inst.m -o inst_method_without_inst
*/
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#interface Foo : NSObject {
}
- (BOOL)doSomethingWithThis:(NSString *)this;
#end
#implementation Foo
- (BOOL)doSomethingWithThis:(NSString *)this {
NSLog(#"Look, it's this: %#", this);
return YES;
}
#end
typedef BOOL (*my_sel_t)(id, SEL, NSString *);
int
main(void) {
Class cls = [Foo class];
SEL my_sel = #selector(doSomethingWithThis:);
Method m = class_getInstanceMethod(cls, my_sel);
// You could also use +[NSObject instanceMethodForSelector:] to get |m|,
// since |cls| is a kind of NSObject.
my_sel_t f = (my_sel_t)method_getImplementation(m);
BOOL result = f(nil, my_sel, #"Hello from an instanceless instance method invocation!");
NSLog(#"result: %d", (int)result);
return EXIT_SUCCESS;
}
You could get it to work even if the instance method accesses instance variables by allocating memory for it to work with (using either +alloc or class_getInstanceSize() plus malloc()) and passing a pointer to that memory as the first id argument to the implementation instead of nil.
While this is entertaining as an exercise, I can't think of a good reason to not just instantiate the class and use the standard messaging syntax and compiler support. In fact, the only reason we couldn't just do [(Foo *)nil doSomethingWithThis:#"BOO!"] here is that objc_msgSend() special-cases messages to nil with the result that NO is returned and nothing happens.

How can I dynamically create an instance of an class?

Example:
I have 10 view controllers, which are all allocated and initialized in the same way:
UIViewController *controller = [[MyViewController alloc] initWithNib];
(note that -initWithNib is a custom method of a UIViewController subclass)
The next view controller class is OtherViewController, and so on. I want to load the view controllers lazily, just when I need them. But to do that, I need to have some kind of "array" that will give me the corresponding class for a given index, so that I can initialize it.
I ended up creating a method with a big switch-statement, that will just do that nasty allocation and initialization separately for every single view controller. I'm not happy with that. There it would be much better if I could assign the appropriate class to a variable, and then at the end of the switch statement just allocate and initialize that class from the variable.
Is there a way to achieve that?
EDIT: I've found a function
id class_createInstance(Class cls, size_t extraBytes)
and every class seems to have a property "class". But I can't assign it to an instance variable. This doesn't work:
Class cls = [UIImage class];
cls *image = [cls imageNamed:#"avatar.png"];
The first line compiles. But the second one gives an error: "image undeclared".
If you know the names of the classes at compile time, you can assign the classes to Class variables. For example:
static Class factory[2];
factory[0] = [MyViewController1 class];
factory[1] = [MyViewController2 class];
...
Then you could have (classid would be a constant known at compile time that would map to a desired class:
-(UIViewController*)createViewController:(int)classid
{
return [[factory[classid] alloc] init];
}
Assuming that method is defined in a class named MyFactory, you can then do:
MyFactory * fac = [[MyFactory alloc] init];
UIViewController * v1 = [fac createViewController: 0]; // typed
id v2 = [fac createViewController: 1]; // untyped
If you don't have the compile time name of the class, you can simply do the following:
#include <objc/objc-runtime.h>
id object = [[NSClassFromString(#"TheClassName") alloc] init];
Since your original question involves a set of UIViewControllers though, there's no reason to lose type safety with the latter method.
You want to use reflection:
id controller = class_createInstance(NSClassFromString(#"your class name"), 0/*extra bytes*/);
Objective-C Runtime Reference
I blogged about this last month at:
http://igotosoft.blogspot.com/2009/05/dynamically-creating-viewscontrollers.html
Essentially, it involves a new class I call the ClassConstructor, which takes a class name, init method name, and comma separated arguments. When you need to create an instance of that class, just use your [myClassConstructor create];
What you want is Reflection. No idea of objective-c has it though - but the term might help you Google for your answer better.
The Objective C Reference also will be a good place to look to get the calls. Try searching for Objective-C 2.0 Runtime Reference since I cant add links