How do I call a method from an instance of a class? - objective-c

-(NSDictionary *)properties;
+(NSDictionary *)ClassProperties;
Now, how can I call ClassProperties from sub-classes?
-(NSDictionary *)properties {
return [? ClassProperties];
}
The point is that ClassProperties gets the list of properties in the class, so i can't call the base class definition.

Along the lines of Marc's response, you could more generally call the method with
[[self class] ClassProperties]
In fact, if your base class and all the subclasses implement + (NSDictionary *)ClassProperties, then your base class can do this
- (NSDictionary *)properties {
return [[self class] ClassProperties];
}
and then none of your subclasses will need to know about - (NSDictionary *)properties. The correct class method would be called based on what self is.

You can just use the class name of the subclass.

Related

Objective-C Class Method

My header class looks like:
#import "Card.h"
#interface PlayingCard : Card
#property (strong, nonatomic) NSString *suit;
#property (nonatomic) NSUInteger rank;
+ (NSArray *) validSuits;
+ (NSUInteger) maxRank;
#end
And my implementation:
#implementation PlayingCard
+ (NSArray *) validSuits
{
return #[#"♥︎", #"♣︎", #"♦︎", #"♠︎"];
}
+ (NSArray *) rankStrings
{
return #[#"?", #"1", #"2", #"3", #"4"];
}
- (void)setSuit:(NSString *)suit
{
if ([[PlayingCard validSuits] containsObject:suit])
{
_suit = suit;
}
}
- (NSString *)suit
{
return _suit ? _suit : #"?"; // if suit !nil return suit, else return ? string.
}
+ (NSUInteger)maxRank
{
return [[self rankStrings] count] - 1;
}
#end
So I understand that any method with a + means it's a Class method.
My question is, why must I use [PlayingCard classMethod] e.g. [PlayingCard validSuits] in the setSuit method whereas I can use [self classMethod] e.g. [self rankStrings] in the maxRank method?
I'm assuming it's something to do with the maxRank method being a class method whereas setSuit isn't. But could it be because setSuit is a setter?
I really don't know, I can't visualise what's going on here. I've only just started my foray into Objective-C and am coming from a Java background.
I have realised I can substitute PlayingCard in for self in the maxRank method without any error messages, however substituting self in for PlayingCard in the setSuit method gives me an error saying
No visible #interface for 'PlayingCard' declares the selector for 'validSuits'
Any explanation as to why this is the case and what's going on would be great. Thanks!
The meaning of self in methods
Every Objective-C method receives an implicit self argument. Instance methods receive the instance, while class methods receive the class object (remember: classes are objects).
If you want to send a class method, the compiler lets you use two types of syntax:
[ClassName classMethod]
[classObjectPtr classMethod]
The first syntax is used in [PlayingCard maxRank]. Here, the target is (explicitly) the PlayingCard class.
A class method already has a class object as a target for sending class methods: the self argument. So they can use [self classMethod] to send other class methods.
Why sending a message to self in class methods?
The advantage of the latter is that the class is not explicitly named. This makes it possible to override class methods in subclasses and call them from base classes.
You basically get the same dynamic method dispatch as with instance methods. This is actually a nice feature of Objective-C not present in Java or C++.
Instance methods would use the dynamic version by accessing their class and sending the message to that:
- (void)setSuit:(NSString *)suit
{
if ([[[self class] validSuits] containsObject:suit])
{
_suit = suit;
}
}
Now an imaginary subclass of PlayingCard could override the class method validSuits and implicitly alter the behavior of setSuit:.
self can be an instance or a class depending on the type of method declared.
- (void)setSuit: is an instance method, thus self is an instance inside this method declaration.
+ (NSUInteger)maxRank is a class method, thus self is a class inside inside this method declaration.
+ (void)classMethod;
- (void)instanceMethod;
- (void)setSuit
{ // self is an instance here
[self classMethod]; // warning, class method sent to instance
[self instanceMethod]; // works, instance method sent to instance
}
+ (NSUInteger)maxRank
{ // self is a class here
[self classMethod]; // works, class method sent to class
[self instanceMethod]; // warning, instance method sent to class
}
You tried to called a "class method" on self inside an instance method where self in an "instance".
In a class method, self refers to the class (it refers to an object that represents the class that obj-c runtime creates for you), so you can use it to call class level method.
In an instance method, self refers to the instance. If you want to call class level method in an instance method, you need to use the class name instead.
Java analogy of obj-c class methods is the static method. Java's this keyword is similar to self, except it can't be used to refer to a class.
setSuit is an instance method, and validSuits is a class method. However, both maxRank and rankStrings are class methods. Class methods are basically the same as static methods in C++

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.

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.

How to call a method of super.super?

I want to call a method of super class of a super class, without breaking the inheritance chain. Something like this:
+(id) alloc
{
return [super.super alloc];
}
Is there a way to achieve this ?
Do not confuse with behavior offering by superclass method, discussed here.
UPD:
A few words about super and superclass differences.
Lets say, we have AClass and SuperAClass. As follows from their names AClass inherits SuperAClass. Each of them has an implementation of a method -(void) foo;
AClass implements one of the following class methods:
1. superclass:
+(id) alloc {
return [[self superclass] alloc];
}
2. super:
+(id) alloc {
return [super alloc];
}
Now, suppose these 2 lines of code:
AClass *AClassInstance = [AClass alloc];
[AClassInstance foo];
In first case (using superclass), SuperAClass's foo method will be called.
For the second case (using super), AClass's foo method will be called.
In your particular example, +superclass is actually the way to go:
+ (id)someClassMethod {
return [[[self superclass] superclass] someClassMethod];
}
since it is a class method, hence self refers to the class object where +someClassMethod is being defined.
On the other hand, things get a tad more complicated in instance methods. One solution is to get a pointer to the method implementation in the supersuper (grandparent) class. For instance:
- (id)someInstanceMethod {
Class granny = [[self superclass] superclass];
IMP grannyImp = class_getMethodImplementation(granny, _cmd);
return grannyImp(self, _cmd);
}
Similarly to the class method example, +superclass is sent twice to obtain the supersuperclass. IMP is a pointer to a method, and we obtain an IMP to the method whose name is the same as the current one (-someInstaceMethod) but pointing to the implementation in the supersuperclass, and then call it. Note that you’d need to tweak this in case there are method arguments and return values different from id.
Thanks to Bavarious who inspired me to involve some runtime staff.
Briefly, the desired hypothetical line:
return [super.super alloc];
can be transformed in this "real" one:
return method_getImplementation(class_getClassMethod([[self superclass] superclass], _cmd))([self class], _cmd);
To make it relatively more clear, it can be expanded as follow:
Method grannyMethod = class_getClassMethod([[self superclass] superclass], _cmd);
IMP grannyImp = method_getImplementation(grannyMethod);
return grannyImp([self class], _cmd);

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!