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];
Related
We're all familiar with the following pattern for instantiating instances of a class:
+ (instancetype)createInstance {
return [[self alloc] init];
}
This works because "self" in this case refers to the class rather than an object built from the class blueprint.
We also know this declaration, most commonly used in avoiding retain cycles:
typeof(self) someStrongSelf = self;
This is allows self's type to be dynamic and that code could be copy-pasted wherever needed no matter the class.
My question deals with combining the above two patterns when instantiating from a class method:
+ (instancetype)createInstance:(MyObject*)dependency {
typeof(self) instance = [[self alloc] init];
instance.dependency = dependency;
return instance;
}
This won't work because self is a class, and a typeof(class) is just a Class, but is there some mechanism for local variables equivalent to instancetype that would allow me the same flexibility as typeof(instance)? For example:
+ (instancetype)createInstance:(MyObject*)dependency {
instanceof(self) instance = [[self alloc] init]; //desired keyword
instance.dependency = dependency;
return instance;
}
If I really wanted this formalized, I know an alternative to this would be defining a protocol that does basically the same thing as above, but I'm curious if Objective-C allows the desired declaration style out of the box.
I understand what you're looking for, but there is no instanceof(self) pattern. The following achieves what you want, though admittedly doesn't have the elegance of typeof(self) pattern:
#interface Foo: NSObject
#property (nonatomic, copy) NSString *string;
#end
#implementation Foo
+ (instancetype)fooWithString:(NSString *)string {
Foo *foo = [[self alloc] init];
foo.string = string;
return foo;
}
#end
#interface Foobar: Foo
// perhaps some more properties here
#end
#implementation Foobar
// and perhaps some more methods here
#end
This implementation demonstrates that the convenience method still allows subclassing. I.e., you can do:
Foobar *foobar = [Foobar fooWithString:#"baz"];
And the resulting object will be a Foobar instance.
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];
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.
I need to move the same method from 4 different classes to the superclass.
Such methods are exactly the same except for the type of a variable declared in them:
For example, in the method in the first class I have
FirstClass var = [[FirstClass alloc] init]
in the second class
SecondClass var = [[SecondClass alloc] init]
and so on.
What's the best way to implement this variation in the superclass ?
Should I use NSClassFromString in the superclass and get each string from each method in the subclasses?
thanks
I'm not 100% sure I get what you mean. So I could be answering the wrong question
If inside your class you need to use an object (I've called it worker below) to do your work, but the class of this object is not known til later, you can use dependency injection (DI).
MyClass.h
#interface MyClass : NSObject
#property (nonatomic, retain) id<WorkerInterface> worker;
#end
MyClass.m
#implementation MyClass
#synthesize worker = _worker;
- (void)myMethod;
{
[self.worker doSomething];
}
// You could also provide a default class to use if one is not passed in
//
// - (id<WorkerInterface)worker;
// {
// if (!_worker) {
// _worker = [[DefaultWorker alloc] init];
// }
// return _worker;
// }
#end
Now whenever I instantiate this class I can simply pass in the appropriate object to be used e.g:
MyWorkerClass *worker = [[MyWorkerClass alloc] init]; // <- Conforms to #protocol(WorkerInterface)
MyClass *instance = [[MyClass alloc] init];
instance.worker = worker;
[instance doSomething];
If all the different types of iVar's you intend on initializing in the subclasses are descended from a common class, then I'd store that class in the super, or else just store it as an id. Then, setup a property accessor in each of your subclasses the casts the iVar as you need it.
#interface superClass : NSObject{
id _superIvar;
}
#end
#implementation superClass : NSObject
....super's code....
#end
Now in the implementation of the subclass declare a property in a category, shown below (or in the interface, if you want it public)
#interface subClass (private)
#property (strong) ClassType *superIvar;
#end;
#implementation
- (void) setSuperIvar:(ClassType *)superIvar{
_superIvar = superIvar;
}
- (ClassType *) superIvar{
return (ClassType *) _superIvar;
}
- (void) someMethodThatUsesSuperIvar{
[self.superIvar doSomething];
}
#end
Alternatively, if you don't want to open your _superIvar to direct access, you can set a property on the superclass and access through the property on the subclass. But in this way you can easily access super's ivars cast to the appropriate type.
Let's say we have a class Base.
#inerface Base : NSObject
{
}
+(id) instance;
#end
#implementation Base
+(id) instance
{
return [[[self alloc] init] autorelease];
}
-(id) init
{
...
}
#end
And we have a derived class Derived.
#interface Derived : Base
{
}
#end
Which reimplements the init method.
Now we want to create an instance of Derived class using class method +(id) instance.
id foo = [Derived instance];
And now foo is actually a Base class.
How to achieve foo to be a Derived class in this case?
Should I reimplement all the class method for derived classes ? (actually immplementation will be totally the same).
Is there a more elegant way ?
When you create an instance using [Derived instance], that instance will be of class Derived. Try it. The trick is messaging self in the instance method:
+(id) instance
{
return [[[self alloc] init] autorelease];
}
When you send the instance message to Base, self is Base. When you send the same message to Derived, self is Derived and therefore the whole thing works as desirable.