How does one detect the calling class from within a static method such that if the class is subclassed the subclass is detected? (See comment inside MakeInstance)
#interface Widget : NSObject
+ (id) MakeInstance;
#end
#implementation Widget
+ (id) MakeInstance{
Class klass = //How do I get this?
id instance = [[klass alloc] init];
return instance;
}
#end
#interface UberWidget : Widget
//stuff
#end
#implementation UberWidget
//Stuff that does not involve re-defining MakeInstance
#end
//Somewhere in the program
UberWidget* my_widget = [UberWidget MakeInstance];
I believe the appropriate solution for what you are trying to accomplish is this:
+ (id) MakeInstance{
id instance = [[self alloc] init];
return instance;
}
And as Cyrille points out, it should probably return [instance autorelease] if you want to follow convention (and aren't using ARC).
UIAdam's solution is perfectly fine for your case. Although if you want to detect, more specifically, from which class is you method called, use [self class] on objects, or simply self for classes.
Related
Is it possible at Objective C at init method to return an instance of different classes?
I'm having a Class called: MyCustomClass. I also have two other different classes called Class 1 and Class2. What I'm trying to implement is: When I call [[MyCustomClass alloc] initWithSomeParameters to create instance of Class1 or Class2 depending on some condition.
MyCustomClass.m:
#import "MyCustomClass.h"
#import "Class1.h"
#import "Class2.h"
-(id) initWithSomeParameters: (id) params{
id myClass;
if (someCondition){
myClass = [[Class1 alloc] initWithSomeParameters:(id) params];
[myClass setSomething:something];
}else{
myClass = [[Class2 alloc] initWithSomeParameters:(id) params];
[myClass setSomething:something];
}
return myClass;
}
...and later I call
id myCustomClass = [[MyCustomClass alloc] initWithSomeParameters:(id) params];
Is this a wrong approach? If so, what would be the correct one?
Several others have mentioned this, but the result of calling [[MyClass alloc] init] must always be nil or a kind of MyClass. It doesn't have to specifically be an instance of MyClass; one of its descendants is possible, as with NSArray or NSString. In code, this requirement would look like:
MyClass *a = [[MyClass alloc] init];
NSAssert((a==nil) || [a isKindOfClass:[MyClass class]], #"This must always hold true.");
I've never attempted to implement this, but it would probably have to look something like this:
- (id)initAsSubclass:(NSString *)sublcassName
{
Class c = NSClassFromString(subclassName);
self = [[c alloc] init];
if (self) {
// Do Custom Init Here
}
return self;
}
The keys would be:
DO NOT perform [super init].
Create a completely new object with +alloc.
Assign the newly created object to self.
If not using ARC, perform [self autorelease], before replacing the value. (If the object that is currently executing code becomes deallocated, it can cause issues. -autorelease will defer that until this section is complete.)
You should make some kind of controller, which initializes correct classes. You can also achieve same that using class methods.
ANd in genreal this given implementation is bad, because you alloc memory once [MyCustomClass alloc] and then in -(id)initWithSomeParameters:(id)params you are allocating memory again. So, even different address will be retruned, that isn't agains apple guidelines, some apple classes also have such behavior, but they do it because of optimizations. But here it is wrong.
Its not a good approach. Its better use some helper class or us factory pattern and provide parameters to method. Then depending on parameters create an object of class and return.
Its not good approach to create object of different class in init method of different class.
Edit:
if You want to show UIView or UIAlertView depending on iOS version do like this.
#interface AlertHelper : NSObject
+ (id)getAlert;
#end
///
#implementation AlertHelper
+(id)getAlert{
NSString *version = [[UIDevice currentDevice] systemVersion];
int ver = [version intValue];
if (ver < 7){
//For iOS 6
return something;
}
else{
//for ios 7
return something
}
}
#end
The way to do it is like this:
Create Base class like:
#import "Base.h"
#import "Class1.h"
#import "Class2.h"
#implementation Base
+ (id)classWithParams:(id)params
{
id retVal = nil;
if (condition_based_on_params_means_creating_class1)
{
retVal = [[Class1 alloc] initWithSomeParameters:params];
}
else
{
retVal = [[Class2 alloc] initWithSomeParameters:params]
}
return retVal;
}
#end
Class1 inherits from Base:
#interface Class1 : Base
{
}
- (id)initWithSomeParameters:(id)parameters;
#end
Class2 inherits from Base:
#interface Class2 : Base
{
}
- (id)initWithSomeParameters:(id)parameters;
#end
Ultimately you will have:
Base* a = [Base classWithParams:yourParams];
I have a superclass and subclasses in the following format:
ParentClass.h
#interface ParentClass : NSObject
-(ParentClass *)field:(NSArray *)fields;
#end
ParentClass.m
#import "ParentClass.h"
#implementation ParentClass
-(id)init{
self = [super init];
if (self == nil) {
return self;
}
return self;
}
-(ParentClass *)field:(NSArray *)fields{
ParentClass *pc = [[ParentClass alloc] init];
// code
return pc;
}
#end
Subclass.h
#interface Subclass : ParentClass
-(Subclass *)field:(NSArray *)fields;
#end
Subclass.m
#import "Subclass.h"
#implementation Subclass
-(id)init{
self = [super init];
if (self == nil) {
return self;
}
return self;
}
-(Subclass *)field:(NSArray *)fields{
// code
return (Subclass *)[self field:fields];
}
#end
I guess the issue is here.
return (Subclass *)[self field:fields];
I'm not accessing the parent class method the way I should. Can anyone tell what should be the right way instead?
What if i call this way?
-(Subclass *)subClassField:(NSArray *)fields{
return (Subclass *)[self field:fields];
}
and i replaced the
-(Subclass *)field:(NSArray *)fields;
with
-(Subclass *)subClassField:(NSArray *)fields;
First please note that this code
-(ParentClass *)field:(NSArray *)fields{
ParentClass *pc = [[ParentClass alloc] init];
// code
return pc;
}
Doesn't look right from the software design perspective. From what you posted it seems that ParentClass instances can create and return other instances of its own type from the field method. This doesn't look ok, but it could be fine depending on what your intentions are.
Consider making ParentClass and FieldClass different classes if that makes sense.
Regarding the subclass, the way of doing what you want would be this:
-(ParentClass *)field:(NSArray *)fields
{
// code
return [super field:fields];
}
Note that I changed the returned type to be (ParentClass *), and the self to super. You cannot return a ParentClass object in the place of a SubClass object (the latter could have extra data that former doesn't know about). Doing the opposite is valid (you can return a Subclass object when someone expects to receive an object of ParentClass type).
Having said that is pretty unclear what you're trying to achieve, I'll tell what's wrong. First of all isn't enough to cast a pointer to a base class pointer, to call the superclass method, you should call it this way:
return (Subclass*) [super field:fields]; // Still wrong
But you're break polymorphism, and as the method signature says, you're returning a Subclass object, and the user that calls this method expects to have a Subclass object, but at the first call of a method that is just implemented by the subclass, it crashes because you're returning an instance of the superclass. Maybe is enough for you to change the method signature to return a ParentClass pointer, but this makes the method useless, why overriding it? It isn't pretty clear what you're trying to do, and what's your logic path.
Edit
Having seen the code that you posted on Github, here the situation is pretty different. In the Java code,t he method field returns this, so no new object gets created, and the method is just used for side effects. The add method doesn't break polymorphism, because just the object reference is of the parent class type, but if executed on a subclass it returns the object itself (this), which is of the subclass type.
In Objective-C for these cases the id type is used, which is used to represent a whatever object pointer, to a whatever class. You could also use the ParentClass type, but I'll stick to conventions. Here's an indicative code:
#implementation ParentClass
#synthesize endpoint
- (id) add: (NSString*) endpoint fields: (NSArray*) fields
{
<code>
return self;
}
- (id) field: (NSArray*) fields
{
return [self add: self.endpoint fields: fields];
}
#end
#implementation SubClass
- (id) field: (NSArray*) fields
{
< Additional code >
return [self add: self.endpoint fields: fields];
}
#end
What is the difference of using:
+ (id) myMethod;
// Rather than
- (id) myMethod;
Using a + declares the method as a class method, or a method that can be called directly on the class, where the class is the object. So when you have this:
#implementation Foo
+(NSString*)method1 {
return #"Foo";
}
-(NSString*)method2 {
return #"Foo";
}
#end
The methods are called in different ways:
[Foo method1]; //=> #"Foo"
Foo* f=[[Foo alloc] init];
[f method2]; //=> #"Foo"
One other thing to note is that class methods don't have access to an instance, which means they can't access any kind of instance variables.
#Linuxios pretty much summed up the concept of class and instance method. However, since you mentioned getters and setters in your title, I want to point out that in Objective-C you can use properties instead of writing your own accessor methods. For example,
In the header file, you will have something like this:
#interface MyObject : NSObject
#property (nonatomic,retain) NSSet* mySet;
#end
In the m file, you wil have something like this:
#implement MyObject
#synthesize mySet;
#end
To access the set in another class you can do it like this:
myObject.mySet; // assuming myObject is an instance of the MyObject class
The top one is a class method (no instance required)
The second one is a instance variable (attached to a specific instance).
This answer explains the methods quite well:
Method Syntax in Objective C
[MyObject myMethod]; // did not have to create an instance
MyObject* myNewObject = [[MyObject alloc] init] autorelease];
[myNewObject myMethod]; // had to create an instance
Here is my code:
//ECHOAppDelegate.m
#implementation ECHOAppDelegate
...
#end
//PtyView.m
#interface PtyView (PtyPrivate)
-(void)startTask;
-(void) didRead: (NSNotification *)fileNoty;
#end
#implementation PtyView
...
-(void)startTask {
//starts task
}
#end
Now, how do I trigger "startTask" from ECHOAppDelegate.m? I need to create an instance? I'm a total beginner :D
Any example code would be awesome!
Thanks,
Elijah
-(void)startTask; appears to be private implementation and in theory should not be called from external classes.
To answer your question, you can call it something like this:
PtyView *v = [[PtyView alloc] init];
[v startTask];
[v release];
Though you will get a warning saying, PtyView might not respond to startTask. Since it is not in public interface of class.
Update: Above code assumes that when startTask returns, you are done with this object. But something tells me that you might be using async callbacks. If that is the case then startTask might return immediately and you won't release it then and there. Normally in this case, you will be notified by PtyView about the completion of task. So you release it when the task is complete.
Update2:
Making a method public is easy. You just declare it in the public interface (the header file of class):
//in PtyView.h
#interface PtyView
-(void)startTask;
#end
//in PtyView.m
#implementation PtyView
...
-(void)startTask {
//starts task
}
#end
Notice that there is no category defined in the interface declaration.
self represent the current object.
You just need to call the method like that.
[self startTask];
How about subclassing ECHOAppDelegate? (Then make sure PtyView inherits from NSObject?)
// cf. http://amath.colorado.edu/pub/mac/programs/PseudoTTY.zip
#interface ECHOAppDelegate : PtyView
...
#end
#implementation ECHOAppDelegate
- (id) init
{
self = [super init];
if (!self) return nil;
...
return self;
}
...
[self startTask];
...
#end
I have class X, an abstract class, and classes A and B that inherit from it. Classes A and B each have their own 'return_something' function. I have another method elsewhere that calls 'return_something' on a series of objects, all of type X. 'return_something' returns something different depending on whether it is an A or a B, so I can just call id *result = [x return_something).
I can design this all fine, but when I come to implementing it I don't know what to put in class X, the parent. It needs to have a 'return_something' function in order for it to be callable, but the function itself is defined in the child classes. I can declare it in the parent and both children, but I don't have anything to return from the X implementation - the returned object is dependent on the child's re-definition.
This would be fine for a non-returning method, but how am I meant to use inheritance and polymorphism with a function?
The simplest thing to do is throw an exception from the "base" function. That way you'll know if it gets called by mistake.
Other languages which provide explicit "abstractness" don't require method bodies for abstract methods.
Use an objective-C protocol instead of an abstract base class:
#protocol ProtocolX
-(int)return_something;
#end
#interface ClassA : NSObject <ProtocolX> {
}
-init;
-(int)return_something;
#end
#interface ClassB : NSObject <ProtocolX> {
}
-init;
-(int)return_something;
#end
#implementation ClassA : NSObject <ProtocolX>
-(int)return_something { return 1; }
-init { retur [super init]; }
#end
#implementation ClassB : NSObject <ProtocolX>
-(int)return_something { return 3; }
-init { retur [super init]; }
#end
References of type id<ProtocolX> can then be passed around and used:
id<ProtocolX> ref = [[ClassA alloc] init];
int myIntForA = [ref return_something];
[ref release];
ref = [[ClassB alloc] init];
int myIntForB = [ref return_something];
[ref release];