开发者

Objective C: Class Method Explanation

As a part of my transition process from C++ to Objective-C, I intensively read book Cocoa and Objective C Up and Running.

In one of the book code examples, there is a line that does not make sense to me with my current level of knowledge:

It is a declaration of class method + (Photo*) photo;.

Could anybody explain me the reason, please, why the author had decided for the method (Photo*) photo; to declare it as a class method instead of instance method?

I have studiet the theory, that the instane method is something like a class member function and that class method is something like static function in C++. But this still does not answer my question.

Here is the declaration code:

#import <Foundation/Foundation.h>


@interface Photo : NSObject{

    NSString* caption;
    NSString* photographer;    
}

+ (Photo*) photo;

- (NSString*) caption;
- (NSString*) photographer;

- (void) setCaption: (NSString*)input;
- (void) setPhotographer: (NSString*)input;

@end

The implementation code follows:

#import "Photo.h"


@implementation Photo

- (id)init
{
    self = [super init];
    if (self) {
        [self setCaption:@"Default Caption"];
        [self setPhotographer:@"Default Photographer"];
    }

    return self;
}


+ (Photo*) photo {
    Photo* newPhoto = [[Photo alloc] init];
    return [newPhoto autorelease];
}


- (NSString*) caption {
    return caption;
}


- (NSString*) photographer {
    return photographer;
}


- (void) setCaption:(NSString *)input {
    [caption autorelease];
    caption = [input retain];
}


- (void开发者_如何转开发) setPhotographer: (NSString *)input {
    [photographer autorelease];
    photographer = [input retain];
}


- (void)dealloc
{
    [self setCaption:nil];
    [self setPhotographer:nil];

    [super dealloc];
}

@end


The + (Photo*) photo method is a Factory Method that encapsulates the details of creating an object of the Photo class.

A Factory Method enforces encapsulation, and allows an object to be requested without inextricable coupling to the act of creation.

In this particular example the information being hidden by the factory method is memory management, since the client does not need to worry about releasing the returned object.

It is a common practice in Objective-C APIs to provide factory methods in classes that return autoreleased objects of that same classes. These methods must not contain any of the words “alloc”, “new”, “copy”, or “mutableCopy”, which, according to the convention, indicates that the caller doesn't own the returned object, i.e. it doesn't have to be explicitly released.

Related resources:

  • Memory Management Rules


Meta answer:

One issue; that method should be declared as returning id and should return [[[self alloc] init] autorelease]; (one line or two, doesn't matter -- just should refer to the Class directly). As it is, Photo is gonna be a pain to subclass.

Expanding -- given this:

+ (Photo*) photo {
    Photo* newPhoto = [[Photo alloc] init];
    return [newPhoto autorelease];
}

If the class were subclassed, this factory method would not work without being overridden to do pretty much the same thing. However, since Objective-C doesn't support co-variance and contra-variance, there would be no way to declare the subclass's implementation of +photo to return an instance of the subclass without also running a significant risk of compiler warnings. Alternatively, you could down-cast the return value to the more specific class, but that is rife with fragility.

Instead, do this:

+ (id) photo {
    id newPhoto = [[self alloc] init];
    return [newPhoto autorelease];
}

This fixes both issues:

  • since it uses self, it'll instantiate an instance of whatever class it is implemented on, including subclasses of Photo.

  • since it returns id, callers can do both of the following without issue:

    Photo *p = [Photo photo]; SubclassOfPhoto *s = [SubclassOfPhoto photo];


In this scenario, photo is a convenience method, which returns you an autoreleased instance of the class.

Since the purpose of photo is to give you an instance, it wouldn't make sense to make it an instance method which would require you to already have an instance.

If you're familiar with Factory Methods, the photo method is similar to that.


+photo is like a constructor. You need a way to get an object to send instance methods to, and this gives you an autoreleased one.


It is equivalent to a static method, as you say. In this case (and all cases of [ClassName className] methods) it's basically a factory method. You're asking the class to construct an instance of itself and pass it back. All such methods should return an autoreleased object.

You can safely ignore methods like that if you want - there will usually be an alloc+init equivalent, but it's often more convenient to use the class method, especially if you're creating a throaway object and don't want to retain it.

Finally, you'll sometimes find classes which require you to use the class method, as they'll hide some clever logic wherein an instance of another class is actually returned. You'll sometimes hear these described as 'class clusters'.


Could anybody explain me the reason, please, why the author had decided for the method (Photo*) photo; to declare it as a class method instead of instance method?

It's basically a wrapper of the constructor litany. Note the source:

+ (Photo*) photo {
    Photo* newPhoto = [[Photo alloc] init];
    return [newPhoto autorelease];
}

Allocate a new Photo, initialize it, mark it autorelease, and return it. Since it creates the object, there is no object yet to operate upon, ergo this needs to be a class method.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜