Access class methods from an instance in Objective-C - objective-c

Given the following class,
#interface MyBaseClass : NSObject
-(void)printName
+(NSString*)printableName
#end
how can I call the class method +printableName from within the instance method -printName without explicitly referring to MyBaseClass? [[self class] printableName] doesn't compile.
The idea is that subclasses will override +printableName so -printName should polymorphically invoke the appropriate +printableName for its class.

Declare MyBaseClass as
#interface MyBaseClass : NSObject
and your [[self class] name] should compile.
This compiles for me:
#interface MyBaseClass : NSObject
-(void)printName;
+(NSString*)printableName;
#end
#implementation MyBaseClass
-(void)printName
{
[[self class] printableName];
}
+(NSString*)printableName {
return #"hello";
}
#end

Have you tried [object_getClass(this) printableName]?
(But you realize, of course, that you could also just create a version of
-(NSString*)printableName2 {
return [MyBaseClass printableName];
}
in each of your classes and call [self printableName2]?)

From what you are describing, it should work. As you didn't offer your implementation, we won't be able to tell, what is wrong.
Based on this question, I wrote an example code for polymorphism in Objective-C.
It contains inheritance-based polymorphism, but also polymorphism based on formal and informal protocols. May you want check your code against it.
here an excerpt:
#import <Foundation/Foundation.h>
/*
* 1.: Polymorphism via subclassing
*/
#interface MyBaseClass : NSObject
-(void)printName;
+(NSString*)printableName;
#end
#implementation MyBaseClass
+(NSString *)printableName
{
return NSStringFromClass(self);
}
-(void)printName
{
NSLog(#"%#", [[self class] printableName]);
}
#end
#interface MySubBaseClass : MyBaseClass
#end
#implementation MySubBaseClass
#end
//...
int main (int argc, const char * argv[])
{
/*
* 1.: Polymorphism via subclassing. As seen in any Class-aware OO-language
*/
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
MyBaseClass *myBaseObject = [[MyBaseClass alloc] init];
[myBaseObject printName];
[myBaseObject release];
MySubBaseClass *mySubBaseObject = [[MySubBaseClass alloc] init];
[mySubBaseObject printName];
[mySubBaseObject release];
//...
[pool drain];
return 0;
}

Related

Problems with subclasses inheriting class factory methods (Objective-C)

While I'm more than familiar with C#, I'm totally new at Objective C and iOS development. So I'm learning the language. What I don't understand is why the following code throws a compiler error (and yes, this is from the exercises at Programming with Objective C:
SNDPerson:
#interface SNDPerson : NSObject
#property NSString *first;
#property NSString *last;
+ (SNDPerson *)person;
#end
#implementation SNDPerson
+ (SNDPerson *)person
{
SNDPerson *retVal = [[self alloc] init];
retVal.first = #"Ari";
retVal.last = #"Roth";
return retVal;
}
#end
SNDShoutingPerson:
#import "SNDPerson.h"
#interface SNDShoutingPerson : SNDPerson
#end
#implementation SNDShoutingPerson
// Implementation is irrelevant here; all it does is override a method that prints a string
// in all caps. This works; I've tested it. However, if necessary I can provide more code.
// The goal here was for a concise repro.
#end
Main method:
- int main(int argc, const char * argv[])
{
SNDShoutingPerson *person = [[SNDShoutingPerson alloc] person]; // Error
...
}
The error is "No visible #interface for "SNDShoutingPerson" declares the selector "person".
Shouldn't this work? SNDShoutingPerson inherits from SNDPerson, so I would have assumed it got access to SNDPerson's class factory methods. Did I do something wrong here, or do I have to declare the method on SNDShoutingPerson's interface as well? The exercise text implies that what I did should Just Work.
Omit the +alloc when calling the class method:
SNDShoutingPerson *person = [SNDShoutingPerson person];
Briefly:
+ (id)foo denotes a class method. This takes the form:
[MONObject method];
- (id)foo denotes an instance method. This takes the form:
MONObject * object = ...; // << instance required
[object method];
Also, you can declare + (instancetype)person in this case, rather than + (SNDPerson *)person;.
change the line SNDShoutingPerson *person = [[SNDShoutingPerson alloc] person]; // Error
to
SNDShoutingPerson *person = [[SNDShoutingPerson alloc] init];
Cheers.
If you want to call class method:
SNDPerson person = [SNDPerson person];
person is a class method, but you're trying to call it with the incompletely constructed instance returned by alloc. Kill the alloc and just do [SNDShoutingPerson person].
This has nothing to do with subclasses, by the way. You would get the same error if you had written [[SNDPerson alloc] person].

unrecognized selector sent to instance 0x10010c730->Objective C

I am new to programming.I have seen this code.returning a derived class object to the base class.
So that the base class can then point to the derived class methods.
Here a static function in class B is returning its object to the base
class.
base-derivedclass.m
#import <Foundation/Foundation.h>
#import "B.h"
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
[B p];
[pool drain];
return 0;
}
A.h
#import <Foundation/Foundation.h>
#interface A : NSObject {
}
#end
A.m
#import "A.h"
#implementation A
#end
B.h
#import <Foundation/Foundation.h>
#import "A.h"
#interface B : A {
}
+(A*)p;
-(void)display;
#end
B.m
#import "B.h"
#implementation B
+(A*)p
{
NSLog(#"returning derived class object to the base class!!");
return [B new];
}
-(void)display
{
NSLog(#"Hello");
}
#end
p is a class method. In Obj-C you denote class method by using + in method declaration and - to denote instance method. You can call the class method by using this:
// [ClassName methodName];
[B p];
Or you can change p to instance method by this:
- (A *)p;
// and call
// [instanceName methodName];
[dep p];
You can check Objective-C: A Primer to get started with these.
There's also some confusion in your memory management, here:
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
B* der = [[B alloc]init];
[der p];
[pool drain];
You create and drain autorelease pools in order to put things into them (after creation) and then dispose of them right away (as you drain them). But you haven't put anything into the pool. You've used "alloc" to create "der," which means you "own" it for memory management purposes, as opposed to its being put in an autorelease pool where it will be taken care of automatically.
If all I've done is confuse you more, you should probably check out some introductory book on Objective-C. They all cover this topic at some point. Or you could look at Apple's docs on memory management, but they assume you already know certain things. (And it IS confusing, so be patient...)

Objective-C Categories

If I add a category method to a class, such as NSXMLNode:
#interface NSXMLNode (mycat)
- (void)myFunc;
#end
Will this category method also be available in subclasses of NSXMLNode, such as NSXMLElement and NSXMLDocument? Or do I have to define and implement the method as a category in each class, leading to code duplication?
It's available in subclasses!
It will be available in subclasses as Yuji said.
However, you should prefix your method such that there is no risk that it conflicts with any method, public or private.
I.e.:
-(void) mycat_myMethod;
Yes it will be available, I though of check it by code and here it is:
#import <Foundation/Foundation.h>
#interface Cat1 : NSObject {
}
#end
#implementation Cat1
- (void) simpleMethod
{
NSLog(#"Simple Method");
}
#end
#interface Cat1 (Cat2)
- (void) addingMoreMethods;
#end
#implementation Cat1 (Cat2)
- (void) addingMoreMethods
{
NSLog(#"Another Method");
}
#end
#interface MYClass : Cat1
#end
#implementation MYClass
#end
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
MYClass *myclass = [[MYClass alloc] init];
[myclass addingMoreMethods];
[myclass release];
[pool drain];
return 0;
}
The output is:
Another Method

How to access a method by inheritance of #protocols in Objective-C?

I have a program where inheritance of protocols are there say:
#protocol A
-(void)methodA
#end
The protocol which inherits:
#protocol B<A>
-(void)methodB
#end
The class which implements #protocolA method is
#interface classB<B>
#end
#implementation classB
-(void)methodA
{
//somecode
}
#end
Now i wanted the methodA to be called from Some other class:
#implementation SomeotherClass
{
//call of methodA
//????
id<A>obj=[[classB alloc]init];//i have tried it
[obj methodA];// even this is not working
}
How to do that?
Just send the message as usual:
SomeotherClass *obj = [[[SomeotherClass alloc] init] autorelease];
[obj methodA];
Since instances of classB implement protocol B, they also claim to respond to -methodA.
The following compiles and runs without any problems:
MyClass.h:
#import <Foundation/Foundation.h>
#protocol A
-(void) methodA;
#end
#protocol B <A>
-(void) methodB;
#end
#interface MyClass : NSObject <B>
{
}
#end
MyClass.m:
#import "MyClass.h"
#implementation MyClass
-(void) methodA
{
NSLog(#"%s", __PRETTY_FUNCTION__);
}
-(void) methodB
{
NSLog(#"%s", __PRETTY_FUNCTION__);
}
#end
the code:
MyClass *obj = [[MyClass alloc] init];
[obj methodA];
[obj methodB];
[obj release];
You don't say how it fails to work. I would guess that there's a compilation error as you don't implement methodB in your classB.
Another possibility: what happens after you've initialised classB in SomeOtherClass? Are you sure that you get a valid object back? If it returned a nil the run time would be perfectly within its rights to do nothing when you sent the methodA message to it.

How to create a strategy pattern in Objective-C?

I need to develop a strategy pattern where i have a main class with other three classes where i need to refer to the objects of the other three classes using the main class object.To solve this is the strategy pattern will help me? If so please do give me the syntax in Objective-C?
You'll want to look at Objective-C's protocol mechanism. Here's a simple protocol with a single required method:
#protocol Strategy <NSObject>
#required
- (void) execute;
#end
Then you declare a class that fulfills that protocol:
#interface ConcreteStrategyA : NSObject <Strategy>
{
// ivars for A
}
#end
The implementation must provide the -execute method (since it was declared as #required):
#implementation ConcreteStrategyA
- (void) execute
{
NSLog(#"Called ConcreteStrategyA execute method");
}
#end
You can make a similar ConcreteStrategyB class, but I'm not going to show it here.
Finally, make a context class with a property maintaining the current strategy.
#interface Context : NSObject
{
id<Strategy> strategy;
}
#property (assign) id<Strategy> strategy;
- (void) execute;
#end
Here is the implementation. The method that delegates to the strategy's -execute method just happens to be called -execute as well, but it doesn't have to be.
#implementation Context
#synthesize strategy;
- (void) execute
{
[strategy execute];
}
#end
Now I'll make a few instances and put them to use:
ConcreteStrategyA * concreteStrategyA = [[[ConcreteStrategyA alloc] init] autorelease];
ConcreteStrategyB * concreteStrategyB = [[[ConcreteStrategyB alloc] init] autorelease];
Context * context = [[[Context alloc] init] autorelease];
[context setStrategy:concreteStrategyA];
[context execute];
[context setStrategy:concreteStrategyB];
[context execute];
The console output shows that the strategy was successfully changed:
2010-02-09 19:32:56.582 Strategy[375:a0f] Called ConcreteStrategyA execute method
2010-02-09 19:32:56.584 Strategy[375:a0f] Called ConcreteStrategyB execute method
Note that if the protocol does not specify #required, the method is optional. In this case, the context needs to check whether the strategy implements the method:
- (void) execute
{
if ([strategy respondsToSelector:#selector(execute)])
[strategy execute];
}
This is a common Cocoa pattern called delegation. For more information on delegation and other design patterns in Cocoa, see this.
Here's a bit more of a concrete example. You can put each item in a separate file. I've put it all in one file for ease of understanding.
// main.m
// StrategyWikipediaExample
//
// Created by steve on 2014-07-08.
// Copyright (c) 2014 steve. All rights reserved.
//
#import <Foundation/Foundation.h>
/**
Equivalent to Java Interface
All concrete Strategies conform to this protocol
*/
#protocol MathOperationsStrategy<NSObject>
- (void)performAlgorithmWithFirstNumber:(NSInteger)first secondNumber:(NSInteger)second;
#end
/**
Concrete Strategies.
Java would say they "Extend" the interface.
*/
#interface AddStrategy : NSObject<MathOperationsStrategy>
#end
#implementation AddStrategy
- (void)performAlgorithmWithFirstNumber:(NSInteger)first secondNumber:(NSInteger)second
{
NSInteger result = first + second;
NSLog(#"Adding firstNumber: %ld with secondNumber: %ld yields : %ld", first, second, result);
}
#end
#interface SubtractStrategy : NSObject<MathOperationsStrategy>
#end
#implementation SubtractStrategy
- (void)performAlgorithmWithFirstNumber:(NSInteger)first secondNumber:(NSInteger)second
{
NSInteger result = first - second;
NSLog(#"Subtracting firstNumer: %ld with secondNumber: %ld yields: %ld", first, second, result);
}
#end
#interface MultiplyStrategy : NSObject<MathOperationsStrategy>
#end
#implementation MultiplyStrategy
- (void)performAlgorithmWithFirstNumber:(NSInteger)first secondNumber:(NSInteger)second
{
NSInteger result = first * second;
NSLog(#"Multiplying firstNumber: %ld with secondNumber: %ld yields: %ld", first, second, result);
}
#end
#interface Context : NSObject
#property (weak, nonatomic)id<MathOperationsStrategy>strategy; // reference to concrete strategy via protocol
- (id)initWithMathOperationStrategy:(id<MathOperationsStrategy>)strategy; // setter
- (void)executeWithFirstNumber:(NSInteger)first secondNumber:(NSInteger)second;
#end
#implementation Context
- (id)initWithMathOperationStrategy:(id<MathOperationsStrategy>)strategy
{
if (self = [super init]) {
_strategy = strategy;
}
return self;
}
- (void)executeWithFirstNumber:(NSInteger)first secondNumber:(NSInteger)second
{
[self.strategy performAlgorithmWithFirstNumber:first secondNumber:second];
}
#end
int main(int argc, const char * argv[])
{
#autoreleasepool {
id<MathOperationsStrategy>addStrategy = [AddStrategy new];
Context *contextWithAdd = [[Context alloc] initWithMathOperationStrategy:addStrategy];
[contextWithAdd executeWithFirstNumber:10 secondNumber:10];
}
return 0;
}