Subclassing Objective C Class methods - objective-c

I have a question regarding Subclassing and Class methods.
I have a base class MyBaseClass which has a convenience class method
+ (id)giveMeAClassUsing:(NSString *)someParameter;
MyBaseClass is not a singleton.
Now, I wish to create a subclass of MyBaseClass, let's call it MyChildClass. I wish to have the same class method on MyChildClass as well. Additionally, I also wish to initialize an instance variable on MyChildClass when I do that.
Would doing something like this:
+ (id)giveMeAClassUsing:(NSString *)someParameter {
MyChildClass *anInstance = [super giveMeAClassUsing:someParameter];
anInstance.instanceVariable = [[UIImageView alloc] initWithFrame:someFrame];
return anInstance;
}
be valid?
Thanks for all your help (in advance) and for resolving my confusion and clarifying some concepts!
Cheers!

That will work fine.
Possibly better would be to define your convenience constructor in such a way that you don't need to override it:
+ (id)myClassWithString: (NSString *)string {
return [[[self alloc] initWithString:string] autorelease];
}
This will do the right thing no matter which of your superclass or any of its subclasses it is called in.
Then change just the initWithString: method in your subclass to handle the initialization:
- (id)initWithString: (NSString *)string {
return [self initWithString:string andImageView:[[[UIImageView alloc] initWithFrame:someFrame] autorelease]] ;
}

Absolutely that's valid.
One note though is in the superclass, reference the class itself with self, rather than the superclass by name.
This is bad:
// MySuperClass // BAD :(
+ (id)giveMeAClassUsing:(NSString *)someParameter {
return [[[MySuperClass alloc] initWithParam:someParameter] autorelease];
}
But this is good!
// MySuperClass // GOOD! :D
+ (id)giveMeAClassUsing:(NSString *)someParameter {
return [[[self alloc] initWithParam:someParameter] autorelease];
}
Otherwise when you subclass, and then call super you aren't actually initializing the right class. Use of self allows the class being instantiated to vary without overriding the class method.

Related

Objective-C class methods returning parent class objects

I'm trying to add a property to UIBezierPath. So I created a subclass called JWBezierPath. I wanted to have all the class method shorthands also with number parameter, so I created the methods:
+ (JWBezierPath *)bezierPathWithColor:(UIColor *)color {
JWBezierPath *path = [self bezierPath];
[path setColor:color];
return path;
}
The problem is, that [self bezierPath] does return an instance of UIBezierPath instead of my subclass. I also tried using concrete class: [JWBezierPath bezierPath]
How can I solve this issue?
If you do not implement +bezierPath method in your class then superclass implementation will be called that will create instance of UIBezierPath, not JWBezierPath.
In theory it is possible for factory methods in base class to create instances even if those methods won't be overridden, e.g. consider 2 options for factory method in BaseClass:
// Will create instance of child class even if method won't be overriden
+ (instancetype) someObject {
return [self new];
}
vs
// Will always create instance of base class
+ (BaseClass*) someObject {
return [BaseClass new];
}
However considering +bezierPath declaration (+(UIBezierPath *)bezierPath) and your evidence UIBezierPath class is not implemented that way and you have to implement +bezierPath method in your cub class
bezierPath is defined as:
+ (UIBezierPath *)bezierPath
so you might want to use:
JWBezierPath *path = [[self alloc] init];
instead.

How Class Method can access Instance Method ?

I am from Actionscript Background. In Actionscript Class Method can access only Class Methods and Class properties.
But In Objective C,
How Class method gameResultAll can access Instance Method initFromPlist
+(NSMutableArray *)gameResultAll://Class Method
-(id)initFromPlist:(id)plist;//Instance Method
NSMutableArray *gameResults = [GameResult gameResultAll]; // (returns GameResult array)
Why [self init] method is called instead of [super init] to create an instance from class method.
Thanks in advance.
#import "GameResult.h"
#implementation GameResult
#define GAME_RESULT_KEY #"gameresult_key"
#define SCORE_KEY #"score"
+(NSMutableArray *)gameResultAll
{
NSMutableArray *resultArray = [[NSMutableArray alloc] init];
for (id plist in [[[[NSUserDefaults standardUserDefaults] dictionaryForKey:GAME_RESULT_KEY] mutableCopy] allValues])
{
GameResult *gameResult = [[GameResult alloc] initFromPlist:plist];
[resultArray addObject:gameResult];
}
return resultArray;
}
//Designated initialiser
-(id)initFromPlist:(id)plist
{
self = [self init];
if(self)
{
if([plist isKindOfClass:[NSDictionary class]])
{
NSDictionary *resultDictionary = (NSDictionary*)plist;
_score = (int)resultDictionary[SCORE_KEY];
}
}
return self;
}
You asked:
How Class method gameResultAll can access Instance Method initFromPlist
It can access that method because you used the alloc method, which creates an instance of GameResult. Now that you have an instance, you can use instance methods in conjunction with this instance.
By the way, this is a very common pattern, a "convenience" class method that allocates an instance of an object (with alloc) and initializes the object (with init or some permutation of that). Or, as in this case, it can create an array of these objects.
You then go on to ask:
Why [self init] method is called instead of [super init] to create an instance from class method.
I can understand the confusion, but there is an important, yet subtle distinction in the behavior of these two.
Imagine this scenario:
At some future date, you subclass GameResult, e.g. ArcadeGameResult;
You implemented an init method for ArcadeGameResult that initializes some properties unique to this subclass; and
You happen to initialize a ArcadeGameResult instance like so:
ArcadeGameResult *agr = [[ArcadeGameResult alloc] initFromPlist:plist];
Because the initFromPlist uses [self init], it means that the the initFromPlist method of GameResult will end up calling the init method of the object (which in this example, is actually a ArcadeGameResult object). But if initFromPlist in GameResult called [super init] instead, it would not have called ArcadeGameResult's init method and thus initFromPlist would be problematic if ever used in conjunction with a subclass.
Bottom line, unless the method you're calling is the exact same method signature, it's safer to call the self rendition rather than the super rendition. It's a little more flexible in case you ever decide to subclass in the future.
There is a corollary to the counsel. When calling class methods from an instance method, you should refer to [self class] rather than the class name. So, imagine your GameResult class had a class method:
+ (void)someClassMethod
{
// do something
}
If you had some GameResult instance method that was going to avail itself of this method, you might be tempted to write:
- (void)someInstanceMethod
{
// do some stuff
[GameResult someClassMethod];
}
But that's not a good idea. You would instead use the following:
- (void)someInstanceMethod
{
// do some stuff
[[self class] someClassMethod];
}
They look very similar, but the latter lets you implement a someClassMethod in a subclass, and this instance method will still work. If you use the former construct, the subclassed class method wouldn't be called by someInstanceMethod.
These are subtle issues, and probably not critical for your current code sample. But hopefully it illuminates the choice of [self init] versus [super init] in this situation.
In Actionscript Class Method can access only Class Methods and Class properties.
That's not different in Objective-C either (because nothing else would make sense), so:
How Class method GameResultAll can access Instance Method initFromPlist
Only through a valid instance.
Why [self init] method is called instead of [self super] to create an instance from class method.
Because the latter is a syntax error, perhaps? Read a basic Objective-C tutorial.

Find the Selector of a Class method

I'm quite a newbie in Objective C, though I have some background in Java reflection.
Here, I have a classic class method findAll that find all the domain objects from the database. The class Univers directly inherits from DomainObject
#interface DomainObject : NSObject
- (NSString *) execute : (NSString*) method withJson:(NSString*)json;
+ (NSString*)findAll: (NSString*)json;
#end
#implementation DomainObject
- (NSString *) execute: (NSString*) method withJson:(NSString*)json{
method = [NSString stringWithFormat:#"%#%#", method, #":"];
//method is 'findAll:'
NSString* result = [ self performSelector:
NSSelectorFromString(method) withObject:json];// Error here
return result;
}
#end
The code was working when findAll was NOT a class method (ie -findAll declaration), but now I have the error : NSInvalidArgumentException -[Univers findAll:]
It clearly seems that the runtime is looking for an instance method.
Any idea to find my class method ?
Instead of calling
NSString* result = [self performSelector:NSSelectorFromString(method) withObject:json];
you need to call
NSString* result = [[self class] performSelector:NSSelectorFromString(method) withObject:json];
for class methods.
After all it's the object instance's class that supposed to be calling the method, not the instance itself.
Short explanation: NSObject implements - (Class)class; (not to be mistaken with + (Class)class of similar effect, which NSObject implements, too!) which returns the Class object of your instance object. Keep in mind that in Objective-C in addition to plain instance objects, Classes are actual objects, too: objects of type Class, that is (vs. id, NSObject, …).
See the documentation for the -class method here.
Btw, you should probably wrap your method call into an conditional block to prevent exceptions caused by calls to missing methods.
SEL selector = NSSelectorFromString(method);
if ([[self class] respondsToSelector:selector]) {
NSString* result = [[self class] performSelector:selector withObject:json];
}
In general it's a common pattern in Objective-C to call an object's class method by receiving the class object via [object class].
Consider this case of a class called Foo implementing a convenience method for returning an autporeleased instance of itself (to be called via: Foo *newFoo = [Foo foo];):
While it would certainly be possible to implement said method like this (after all we know the object's class name, right?):
+ (id)foo {
return [[[Foo alloc] init] autorelease];
}
the correct way is this:
+ (id)foo {
return [[[self alloc] init] autorelease];
}
As the first one would cause problems with polymorphism in subclasses (Such as a subclass called FooBar, for which it should clearly be [FooBar alloc] …, not [Foo alloc] …. Luckily [[self class] alloc] solves this dynamically).
While this is clearly not the right place for a thorough explanation of this (rather offtopic one might say) it's certainly worth noting/warning about, imho.

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.

What's the correct method to subclass a singleton class in Objective -C?

I have created a singleton class and I want to create a class which is subclass of this singleton class, what is the correct method to do it
I don't know about Objective-C in particular, but in general singleton classes should prevent subclassing. If you've got an instance of the base class and an instance of the subclass, then you've effectively got two objects you can regard as instances of the base "singleton" class, haven't you?
As soon as you've got two instances, it's not really a singleton any more... and that's leaving aside the possibilities that there are multiple subclasses, or that the subclass itself allows multiple instances to be created.
Of course you can change your base class so it just has a way of getting at a single "default" instance, but that's not quite the same as making it a singleton.
If Jon didn't convinced you to not do it, you should do it this way:
In your superclass, init your singleton instance with [[[self class] alloc] init] so then you always get an instance of the class with which you are calling the sharedInstance method. And you don't have to overwrite the sharedInstance method in your subclass.
[SuperClass sharedInstance] //-> instance of SuperClass
[SubClass sharedInstance] //-> instance of Class
I made an example "base class" for singleton, you can check it here: https://github.com/stel/DOSingleton
Jon Skeet makes a good point about whether you’d really have a singleton if you’re allowed to instantiate both the class and its subclass. Putting that aside, here’s a pattern you can use so that so you only have to define the shared-instance getter once, in the parent class:
// this code goes in the implementation of the superclass
static Sprocket *defaultSprocket;
+ (instancetype) defaultSprocket
{
if (defaultSprocket == nil)
defaultSprocket = [[[self class] alloc] init];
return defaultSprocket;
}
This approach has the following advantages:
Using [self class] allows e.g. [SprocketSubclass defaultSprocket] to return an instance of SprocketSubclass instead of Sprocket
Using instancetype allows the compiler to type-check the result of this method: it’ll be Sprocket when you invoke it as +[Sprocket defaultSprocket] but SprocketSubclass when you invoke it as +[SprocketSubclass defaultSprocket].
Notably, you can define this accessor method in the base class and then you don’t have to do anything in the subclasses!
(Hat tips to NSHipster for explaining why instancetype is so cool and bbum for reminding me of it recently.)
If what you are looking for is a quick way to setup new singletons. This pseudo abstract singleton base class is what I use:
Reusable base class
H
#define CREATE_SHARED_INSTANCE \
+ (instancetype)sharedInstance { \
static dispatch_once_t once; \
static id instance = nil; \
dispatch_once(&once, ^{ \
instance = [[self alloc] init]; \
}); \
return instance; \
}
#interface SharedObject : NSObject
+ (instancetype)sharedInstance;
#end
M
#implementation SharedObject
+ (instancetype)sharedInstance {
[NSException raise:#"Call to unimplemented sharedInstance" format:#"%# does not implement sharedInstance.", NSStringFromClass([self class])];
return nil;
}
#end
Then each subclass
H
#import "SharedObject.h"
#interface SomeSubclass : SharedObject
#end
M
#implementation SomeSubclass
CREATE_SHARED_INSTANCE
#end
...and use like any singleton.
[[SomesSubclass SharedInstance] someMethod];
If you call the abstract base class, or forget to include CREATE_SHARED_INSTANCE in your subclass, you will get a friendly exception raised.
This way you can setup a new singletons easily at no performance hit.
The simplest way to achieve this is implement the standard singleton accessor in both the class and the subclass. This way each class behaves as a proper singleton, that is there is only ever one instance of both. If you attempt to reuse the accessor of the parent class in the subclass and then if you make use of both classes, you run the risk of the accessor returning the wrong instance because their behaviour would depend on the order of how they are accessed.
You should not use instancetype for the singleton accessor to help prevent this mistake. You'll notice Apple don't use it for their singletons e.g. UIApplication and CKContainer.
If you would like existing code that accesses the super-class's singleton method be given an instance of the subclass then likely you need to redesign, see MrJre's answer.
I had a similar problem and the way I solved it is to create a singleton wrapper class which has all the extra functionality. This singleton class contains the original singleton (has the singleton instance as a member variable). This way you can avoid dirty tricks.
I had a similar problem, I had multiple targets that needed to have a slightly different singleton implementations: each target would include the base class + a specific subclass. This was achieved by writing the base class like so:
+ (SingletonBaseClass*) sharedInstance {
static SingletonBaseClass * sharedInstance = nil;
if (!sharedInstance) {
sharedInstance = [[[self class] alloc] init];
[sharedInstance customInit];
}
return sharedInstance;
}
The key difference is [self class] instead of the actual class name. That way when the we call: [SingletonSubclass sharedInstance] the correct object is instantiated.
Please note that this is a specific case, in the general case I agree with previous answers.
I had the same problem. This is how to solve: You need to use a static dictionary to subclass a singleton. For exemple:
Class A : NSObject -> Singleton
Class B : A
Class C : A
#implementation A
// Dictionary that holds all instances of API subclasses
static NSMutableDictionary *_sharedInstances = nil;
+ (instancetype)sharedInstance
{
id sharedInstance = nil;
#synchronized(self)
{
NSString *instanceClass = NSStringFromClass(self);
if (_sharedInstances == nil)
_sharedInstances = [NSMutableDictionary dictionary];
// Looking for existing instance
sharedInstance = [_sharedInstances objectForKey:instanceClass];
// If there's no instance – create one and add it to the dictionary
if (sharedInstance == nil)
{
sharedInstance = [[super allocWithZone:nil] init];
[_sharedInstances setObject:sharedInstance forKey:instanceClass];
}
}
return sharedInstance;
}
Now you can use [B sharedInstance] and [C sharedInstance] without problems!