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!
Related
I have two class files hudlayer.m and actionlayer.m
I have a method named jump in hudlayer.m
And i have a method named jumpone in actionlayer.m
-(void) jumpone {
_heroBody->ApplyLinearImpulse(b2Vec2(_playerVelX/[_lhelper pixelsToMeterRatio], 1.25), _heroBody->GetWorldCenter());
}
and another method called jump in hudlayer.m
-(void)jump {
ActionLayer *aob = [[ActionLayer alloc] init];
[aob jumpone];
}
The problem is when i call the Jumpone method from actionlayer.m my sprite jumps (i.e method called)
My init method of action layer
- (id)initWithHUD:(HUDLayer *)hud
{
if ((self = [super init])) {
[self setupWorld];
}
return self;
}
But when i call jumpone via jump method in from hudlayer.m it fails and my app crashed.
Any help will be appreciated .thanks
the best solution for your problem is to add a tag to hudlayer & action layer
ex: hudlayer.tag=1;
actionlayer.tag=2;
and then just use getChildByTag like this:
[[[[CCDirector sharedDirector]runningScene] getChildByTag:1]jumpone];
Everytime you call jump it creates a new instance of you ActionLayer. And following that, you setup a new world and everything get tangled up. Furthermore its a memory leak.
Make you ActionLayer to an iVar of HUDLayer and call
aob = [[ActionLayer alloc] init];
in the HUDs init method.
Dont forget to release aob in dealloc of the HUDLayer
I got a question about subclassing.
I start with my first view:
in my .h file:
#interface viewAController : UIViewController
in my .m file:
-(void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"Begin view");
udpSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
NSError *error = nil;
if (![udpSocket bindToPort:12345 error:&error]) //check ff of dit werkt!
{
NSLog(#"F you");
return;
}
NSLog(#"Derde line");
if (![udpSocket beginReceiving:&error])
{
NSLog(#"Screw you!");
return;
}
}
Porting and beginreceiving goes well.
and then when I subclass viewAController:
#interface viewBController : viewAController
in my .m file:
-(void)viewDidLoad{
[super viewDidLoad];
}
I am expecting that my subclass [viewBController], will display all of the NSLogs, because Im calling the super viewDidLoad.
Instead it is saying: F you!
Oke I understand that I can only bind once to the port, BUT Im expecting an error message, this does not show.
So I delete the binding and then I get Screw you, apparently I cannot say beginreceiving when Im not binding to a port. Without these two methods it works just fine though, it is printing everything out of the parent.
QUESTIONS:
Should I bind? I actually only need to listen to port 12345, should I just implement this differently?
Should I work without bind and without beginreceiving? I think I prefer with binding so that I wont listen to all of my ports.
Why cant I do beginreceiving when I dont bind?
How can I show the error?? Cause it is not printing any errors ...
greetz
What you are doing is right.But i have only one question to ask whether you have added the object of derived ViewController to some View.
Unless you wont add it you wont get the didLoad Of your superclass get fired.
Check by adding the object of your derived View to SomeView.
This is wrong you are doing
NSLog("#Hi there!");
you have to use
NSLog(#"Hi there!");
And if this is a typo (I hope it is) you have to add your sub class to some where using add subview or pushing it.
HERE IS THE CODE: http://min.us/mWdMO0n14
I'm a Obj C newbie, so I've searched quite a bit, but haven't found anything that can solve my problem.
I have CalculatorViewController.h and .m and then CalculatorBrain.h and.m (Stanford Lectures)
in CalculatorBrain.m, I have the following method, with all of the variables defined as private in the CalculatorBrain header.
- (void)clearEverythingOnShakeGesture{
operand = 0;
waitingOperation = #"";
waitingOperand = 0;
}
Then in CalculatorBrain.m , I have everything set up to detect shakes, as follows. I've included some of the code above the shake detection just so you have a general idea.
#interface CalculatorViewController()
#property(nonatomic, retain) CalculatorBrain *brain;
#end
#implementation CalculatorViewController
#synthesize brain;
- (CalculatorBrain *)brain {
if (!brain) {
brain = [[CalculatorBrain alloc] init];
}
return brain;
}
-(BOOL)canBecomeFirstResponder{
return YES;
}
-(void)viewDidAppear: (BOOL) animated{
[super viewDidAppear:animated];
[self becomeFirstResponder];
}
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event {
if (event.subtype == UIEventSubtypeMotionShake)
{
NSLog(#"SHAKE IT!");
[brain clearEverythingOnShakeGesture]; //********** not sure how to call this.
}
}
I'm not sure how to call [brain clearEverythingOnShakeGesture]; , because I get the error "Class method +clearEverythingOnShakeGesture not found, defaults to return type id". However, if I make it a class method, the variables inside are instance variables, which provides another error. Any help greatly appreciated.
The project's AppDelegate posted in the comment above is building the calculator view controller from a nib, then releasing it immediately. The app functions partially, but the UILabel property to be cleared on the shake gesture is nulled at that point.
Also, it's a good practice to declare private properties in the private category, synthesize them with _underscore aliases, and refer to them as self.property outside of synthesized methods.
Are you #import-ing the CalculatorBrain.h? Also, you're using a nice lazy initialization pattern by building the CalculatorBrain in the getter, but you're not calling the getter in the motionBegan: method. Try [self.brain clearEverything ...] to get the brain instance.
I don't see anything in the code that would make the compiler think you have a class method. So that's mysterious. Please double check about the header import. You are correct that the clearEverything... should be an instance method.
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.
I have two objects of class WidgetClass in my stored model. They are saved each time the app exits and reloaded each time it starts. I want to update my model to make one of them a WidgetSubclass object. WidgetSubclass will be a subclass of WidgetClass.
WidgetClass has quite a lot of ivars. WidgetSubclass will add few or none.
What is the most efficient way to accomplish the update? I am not using core data.
Couple of things.
If the subclass does not add any ivars to the superclass, you can actually get away with the following:
WidgetSubclass* widget = (WidgetSubclass*)[[WidgetClass alloc]initWithCoder: someCoder];
Class object_setClass(widget, [WidgetSubclass class]);
There is some risk that changes in the runtime could break the above code. So here is a safer way:
Foo.m:
-(void) copyIvarsTo: (Foo*) foo {
[super copyIvarsTo: foo];
foo.ivar1 = [self.objectIvar1 copy];
foo.ivar2 = [self.objectIvar2 copy];
foo.floatIvar = self.floatIvar;
// etc. Method works fine if foo is actually a member of a subclass.
}
-(Foo*) copy {
Foo* clone = [[self class]alloc];
[self copyIvarsTo: clone];
return clone;
}
Now I can have the following NSObject category method:
-(NSObject*) wj_copyWithSubclass: (Class) subclass {
if (![self respondsToSelector: #selector(copyIvarsTo:)])
return nil;
NSAssert([subclass isSubclassOfClass: [self class]], #"call copyWithSubclass only on subclasses");
NSObject* clone = [subclass alloc];
[self copyIvarsTo: clone];
return clone; // at this point, clone has copied all the ivars that are members of the receiver's class. Other ivars have their default values. Calling code needs to handle that.
}