Can someone help me understanding as why do we call an initialization method on super first before initializing. I came across a piece of code in a subclass of UIView and wanted to know that here myMethod is always getting called that means I am not getting the frame set in UIView, then why are we doing this and using an if condition.
self = [super initWithFrame:CGRectMake(0, 0, 20, 100)];
if(self != nil) {
[self myMethod:data];
self.backgroundColor = [UIColor clearColor];
}
return self;
Let's say I have a UIView subclass called SpinningView. The code to create spinningView would look like this:
SpinningView *spinner = [[SpinningView alloc] initWithFrame:CGRectMake(0.0, 0.0, 20.0, 20.0)]
Now let's take a look at the implementation of SpinningView's -initWithFrame: method
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
self.backgroundColor = [UIColor clearColor];
}
return self;
}
The first line is simple assignment. We're assigning ourselves to the result of UIView's implementation of -initWithFrame:
We use the if statement to see if self is even valid. If it's not we just return it. If it is, we configure it.
This is simply calling the constructor of the super class (in this case UIView).
You need to call UIView's constructor to make sure that all the variables you don't see from your subclass is set up properly, and that's what you do with [super init] (or in this case initWithFrame:).
There are a few other reasons why it looks like this.
First of all [super init] might return nil. Perhaps something went wrong initializing things in the code of the superclass. The check for self != nil makes sure you don't use the object when something is already wrong with the object. It might even have been released by the super constructor.
In other cases the super constructor might actually return a different object altogether. Examples of this happening is with class clusters or when you implement a singleton.
To summarize:
Always call the designated constructor (i.e. init-method).
Always use the standard construct of if ((self = [super init])) { /* own init */ } return self;
Sometimes it looks different, but only for special reasons. If in doubt, always use (2).
Apple's documentation has a lot more info on this is you're interested.
Also, when overriding constructors like this, remember that there might be more than one constructor. For instance, if you add the view using Interface Builder, that view will be initialized using "initWithCoder:" instead. All constructors begin with "init" though.
Related
I have a object derived from UIView, it is AIItem, this item have UIImageView *status_view, now I need another object AIAnotherItem derived from AIItem, problem is in status_view.
For Example :
AIItem init method
-(id)initWithName:(NSString *)name {
self = [super init];
if (self) {
status_view = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,50,50)];
status_view.image = [UIImage imageNamed:#"item_image.png"];
[self addSubview:status_view];
}
}
AIAnotherItem init method
-(id)initWithName:(NSString *)name {
self = [super initWithName:name];
if (self) {
status_view.image = [UIImage imageNamed:#"another_item_image.png"];
}
return self;
}
in AIAnotherItem I set another image to status_view but it won't changed.
Question is why ? and how do this ?
Regardless what the mechanics are of this not working (I am sure you will figure it out), I believe that you are perhaps not going about this the right way.
Would it not be more logical to have class AIItem.h that has an empty property statusView? And then two derived classes (or instances of the same subclass) that inherit the same statusView but fill it with different images?
I think this would correspond more closely to the philosophy behind inheritance.
I have a main game class which renders the game using Open GL. Now I thought I could inherit from this class and then just call [super init] in its init method to get a copy of it. The plan was to make some modifications in the copy but as it seems this doesn't work.
The following is the header file of my class:
#import "GameView.h"
#interface CloneView : GameView {
}
-(id)initWithFrame:(CGRect)frame;
#end
And this is the Clone view class:
#implementation CloneView
-(id)initWithFrame:(CGRect)frame{
return [super initWithFrame:frame];
}
#end
If I set a break point in the init method in the GameView class it stops there. Thing is: my clone view doesn't get rendered, the screen stays black.
What am I missing? Thanks for your help!
Edit
Just for the record: I tried without implementing initFrame and got the same result. (as expected as the initFrame as above isn't doing anything apart from calling super)
Edit 2
I'm adding my clone to another view so I'm creating two Eagle contexts. Could that be the reason why it doesn't work?
If you are not adding anything in the init function of CloneView than you don't even have to rewrite it. You can just have your class inherit from GameView and it automatically copies it's init function.
This is from the apple docs
You should assign self to the value returned by the initializer because the initializer could return an object different from the one returned by the original receiver.
So Try doing this
-(id)initWithFrame:(CGRect)frame{
if(self = [super initWithFrame:frame] ) {
//Do whatever you need to do here.
}
return self;
}
This should fix your issue if you need to do something in your init method. Otherwise you can skip the init method altogether.
try doing this it may work..
return(self=[super initWithFrame:frame])
which ensures the super class method is copied properly to the current method
TNQ
I finally located the problem:
I needed to write a second init method. The problem was that the following code was being executed twice:
CAEAGLLayer *eaglLayer = (CAEAGLLayer *)[super layer];
[eaglLayer setOpaque:YES];
m_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
if (!m_context || ![EAGLContext setCurrentContext:m_context]) {
printf("FAIL \n");
[self release];
return nil;
}
[Textures loadTexture];
if ([self createFramebuffer]) {
[self draw];
}
This code was in the initFrame method of the game class. I made a second init method that does not execute this code. Instead, this code is executed in the parent view class of the clone. Now it works, YAY!!
Thanks for trying to help me!
It must be one of those things where there's a tiny mistake i've missed, or something, but i can't seem to figure it out.
Viewcontroller.h
#import "RGBEditView.h"
#interface ColorPickerView : UIViewController {
RGBEditView *rgbEditView;
}
-(void)showRGBEditor;
.m
-(void)showRGBEditor {
rgbEditView = [[RGBEditView alloc] initWithFrame:CGRectMake(0, 0, 280, 46) H:h S:s B:b];
}
It's this line above, the initwithframe line, that gives the error 'Incompatible Objective-C types assigning '*', expected '*'
RGBEditView.h
#interface RGBEditView : UIView {
}
-(RGBEditView *)initWithFrame:(CGRect)frame H:(float)hue S:(float)saturation B:(float)brightness;
RGBEditView.m
-(RGBEditView *)initWithFrame:(CGRect)frame H:(float)hue S:(float)saturation B:(float)brightness {
[super initWithFrame:frame];
return self;
}
Can anybody see my problem? I'm very confused about this.
EDIT:
The problem lies in that I have another class which also uses initWithFrame:H:S:B:, so the only way to fix this is to change on of them to something a bit different, but this seems like an awkward work around. Any other solutions?
the methods init and methods that start with initWith should return type id.
what typically happens is that you have 2 classes with the same method name (initializer in this case), but differ in their return types:
RGBEditView
-(RGBEditView *)initWithFrame:(CGRect)frame H:(float)h S:(float)s B:(float)b;
HSBEditView
-(HSBEditView *)initWithFrame:(CGRect)frame H:(float)h S:(float)s B:(float)b;
alloc returns id - the compiler warns you because it sees an expression which resembles type assignment used in the following example:
RGBEditView * rgb = /* ... */;
HSBEditView * hsb = nil;
hsb = rgb // << compiler: "hey - you don't want to do that unless
// RGBEditView were a subclass of
// HSBEditView... but it's not!"
you correct this by returning id from your initializers, like this:
-(id)initWithFrame:(CGRect)frame H:(float)h S:(float)s B:(float)b;
you return id to avoid clashes like this, and because the compiler doesn't know what type is returned via alloc, so every subclass declaration would have to return a different type - which would only lead to more problems.
the exception to this is to use well qualified names - and is typically seen in convenience constructors:
+ (HSBEditView *)newHSBEditViewWithFrame:(CGRect)frame
H:(float)h S:(float)s B:(float)b;
in RGBEditView.m try
self = [super initWithFrame:frame];
return self;
initWithFrame should be
-(RGBEditView *)initWithFrame:(CGRect)frame H:(float)hue S:(float)saturation B:(float)brightness {
self = [super initWithFrame:frame];
return self;
}
My iPhone app has an abstract class WorkingView. It is a subclass of UIView. WorkingView will in turn have a bunch of concrete subclasses. Two of those will be SimplifyView and MultiplyView.
I am trying to write the method that creates new instances of WorkingView. This method should have the mode passed in and return an instance of the appropriate concrete subclass. Per the answer to this question, this is what I have so far:
+ (id)newWorkingViewWithFrame:(CGRect)frame mode: (modeEnum) mode {
WorkingView *ret;
switch (mode) {
case simplifyMode:
ret = [[SimplifyView alloc]initWithFrame: frame];
break;
case multiplyMode:
ret = [[MultiplyView alloc]initWithFrame: frame];
break;
// additional cases here
default:
return nil;
}
// more initialization here
return ret;
}
So far, so good. But here is the problem. In SimplifyView's init method, I need to run the object through UIView's init method. Calling [super initWithFrame: frame] gets me only to WorkingView, not all the way to UIView. I suppose I could create an initWithFrame: method in WorkingView that in turn calls UIView's initWithFrame: method -- but that feels hackish.
What is the appropriate way to handle this?
If you call [super initWithFrame:frame] from your subclass, the runtime will climb the inheritance hierarchy looking for a class that implements that method, starting with super. If super doesn't implement initWithFrame:, the runtime will keep climbing until it eventually finds and invokes the default implementation in UIView.
Iam a newbiew to iPhone development. Version of my SDK is 2.2
In my code, UIViewController is used to change view dynamically once the app is launched, a method in the UIViewController is called to know which view should be initialized along with parameters, which goes to a 'switch-case' and assign a view to current view according to the parameter, like this:
case 1:
currentView = [[View01 alloc] init];
break;
case 2:
currentView = [[View02 alloc] init];
break;
and outside the switch-case:
[self.view addSubview:currentView.view];
I wonder f can pass a parameter along with initialization, like iniWithNibName or so? I need this because have to manipulate in the leaded view, according to the view from which its called.
Thanks.
One way to approach this is to modify your View01 and View02 classes to include an initWithParam: initialiser.
i.e. add
- (id) initWithParam:(NSString *)myParam;
to the #interface section and add
- (id) initWithParam:(NSString *)myParam {
if (self = [self init]) {
// handle or store 'myParam' somewhere for use later
}
return self;
}
to the #implementation section. Notice how the initWithParam: message internally calls the existing init. Obviously you could change the type, or number of parameters passed in as required.
Another approach would be to provide a property on your view class, so you could do something like the following:
currentView = [[View01 alloc] init];
currentView.myParam = #"SomeValue";
Which approach works the best will depend somewhat on your particular application needs.