Here's my class with my custom init method:
// Piece.h
#import <Foundation/Foundation.h>
#interface Piece : CCSprite
#property (nonatomic) int pieceNumber;
+(Piece *)initWithPieceImage:(UIImage*)piece pieceName:(int)pName;
#end
// Piece.m
#import "Piece.h"
#implementation Piece
#synthesize pieceNumber = _pieceNumber;
+(id)initWithPieceImage:(UIImage *)piece pieceName:(int)pName
{
return [[[self alloc] initWithPieceImage:piece pieceName:pName] autorelease];
}
-(Piece*)initWithPieceImage:(UIImage *)piece pieceName:(int)pName
{
CCSprite *bgImage = nil;
if ( (self=[super init]) )
{
bgImage = [CCSprite spriteWithCGImage:piece.CGImage
key: [NSString stringWithFormat:#"%i",pName]];
}
return (Piece*)bgImage;
}
#end
I instantiated the Piece class like this to add it to the layer:
Piece *newPiece = [Piece initWithPieceImage:myUIImage pieceName:1];
[newPiece setPieceNumber:2]; //Error in this line
[self addChild: newPiece z:1];
However I have tried it like this and it perfectly works:
Piece *newPiece = [[Piece alloc] init];
[newPiece setPieceNumber:2];
but this is not what I want.
and here is the error I get:
[CCSprite setPieceNumber:]: unrecognized selector sent to instance 0x85f1050
Terminating app due to uncaught exception NSInvalidArgumentException, reason: -[CCSprite setPieceNumber:]: unrecognized selector sent to instance 0x85f1050
Aparently it looks like the problem is how Im trying to init my object.
I'm a newcomer to objective-c so I cant figure out what is wrong here.
any idea of what am I doing wrong here?
How can I achieve this approach and access the properties of my instantiated object with custom init method?
You have a mess in your code. In -(Piece*)initWithPieceImage:(UIImage *)piece pieceName:(int)pName you return a CCSprite object instead of a Piece. You assign self with an object but return another, of an incorrect type.
init returns the correct type (because you haven't reimplemented it), so it works, but you haven't actually initialized the image correctly.
You need to change your method like so:
-(Piece*)initWithPieceImage:(UIImage *)piece pieceName:(int)pName
{
return [super initWithCGImage:piece.CGImage key:[NSString stringWithFormat:#"%i",pName]];
}
It is because in your init method, you are for some reason creating a CCSprite object and returning that instead of the Piece object. Because of that, it will not be an object of your Piece class and will not respond to any of Piece's methods.
Instead of creating a new CCSprite object to set those properties to, you want to set those on self or super.
Related
I'm trying to have another object call a selector. I'm attempting to define this selector from another class by defining the selector property. It doesn't seem to be working like I expect.
ComboBox.h
#property (nonatomic) SEL onComboSelect;
ComboBox.m
-(void)doneClicked:(id) sender
{
[textField resignFirstResponder]; //hides the pickerView
NSLog(#"DONE CLICKED CALLED");
[self performSelector:#selector(onComboSelect)];
}
OtherClass.h
#interface OtherClass : BaseViewController
{
ComboBox *combo;
}
-(void)comboSelector;
OtherClass.m
// in viewDidLoad
combo = [[ComboBox alloc] init];
combo.onComboSelect = #selector(comboSelector);
-(void)comboSelector
{
NSLog(#"COMBO SELECTOR");
}
I see "DONE CLICK CALLED" in the logs, but not "COMBO SELECTOR". So I know doneClicked is being called, but the selector doesn't seem to be working. What am I doing wrong? Is there a better way to do this?
A #selector is just a method name - it does not include any context about the class on which it is defined. So this [self performSelector:#selector(onComboSelect)] is just invoking the method on self. In addition to the selector, you also need a reference to the object on which you want to call it.
Notice how some built-in classes (like UIControl) take both a target object and action selector.
There are a 2 major issues in your code.
1.
onComboSelect is a SEL so no need to use the #selector again.
Instead of:
[self performSelector:#selector(onComboSelect)];
Use :
[self performSelector:onComboSelect];
2.
You are calling the selector on self from ComboBox class, so it'll call the selector on ComboBox object (if defined) not on OtherClass object
Your answers were helpful. Here is what I did:
added to ComboBox.h
#property (nonatomic, weak) UIViewController *parentViewController;
added to ComboBox.m
-(void)doneClicked:(id) sender
{
[textField resignFirstResponder]; //hides the pickerView
if ([parentViewController respondsToSelector:#selector(comboSelector)])
[parentViewController performSelector:#selector(comboSelector)];
}
added to OtherClass.m
combo.parentViewController = self;
#property (nonatomic) SEL onComboSelect <-- This property is not needed in ComboBox.h.
SEL is a point of objc_seletor,and in object_seletor runtime can find the
objc_method ,that define
objc_method {
SEL method_name OBJC2_UNAVAILABLE;
char *method_types OBJC2_UNAVAILABLE;
IMP method_imp OBJC2_UNAVAILABLE;
}
and IMP is the point of method,and you can find this in "runtime.h" file.
Any noe kow how to find objc_method by object_seletor ? and I cannot find the define of objc_seletor struct.
Im writting a Simple SpriteKit game , but I have got a really serious error.
I created a Subclass of SKEmitterNode which i Named GameNode. I need it for some special instance methods. I set a property for this Custom Class(GameNode). Its the following:
#property (nonatomic,assign) nodetype GNodeType;
Yes, i ussing an enum for this property type. My enum is the following:
typedef enum {
nodetypeblue,
nodetypered,
nodetypegreen,
nodetypewhite
}nodetype;
Ok , now what is my problem. When I instance this class with the following custom init method:
-(id)initWithRandomTypeforSkScene:(SKScene*)Scene{
self=[super init];
if (self) {
nodetype type = arc4random_uniform(4);
self.GNodeType=type;
NSString *bluepath = [[NSBundle mainBundle] pathForResource:#"bluenode" ofType:#"sks"];
NSString *pathtoadd = [NSString string];
switch (type) {
case nodetypeblue:
pathtoadd = bluepath;
break;
//I have some possiblilies here i not list them all, its desnt matter
default:
pathtoadd = bluepath;
break;
}
self = [NSKeyedUnarchiver unarchiveObjectWithFile:pathtoadd];
self.position = CGPointMake(arc4random_uniform(Scene.size.width-40)+20, arc4random_uniform(Scene.size.height-40)+20);
//self.name = #"node";
[self setScale:0.25f];
return self;
}
else{
return nil;
}
}
OK, after that, I try to create az instance of this class like this:
GameNode * Node = [[GameNode alloc] initWithRandomTypeforSkScene:self];
//Self is a SKScene here
And here is my problem. This is returning a SKEmitterNode not a GameNode. How I know this? Because whenever i call for the Node.GNodeType the xcode send an Exception with the following error message:
-[SKEmitterNode GNodeType]: unrecognized selector sent to instance 0x10a022f80
Im setted lot of brakepoints and tried that i can, but it didnt solved anything.
Oh and after I create this instance called "Node" I checked, that right after creation the tpye is a SKEmitterNode not GameNode. If i check the type or the GnodeType inside my class everything is OK. I have problems just outside after the creating,initialization.Help please.
With help of LearnCocos2D i succesfully solved the issue.
SO I created a Property for my class which holds an SKEmitterNode. I added the sks to the property and i presented this Property instead of the whole class.
I've implemented 3 classes.
-Scene.m & .h
Scene.m: (has HudLayer & BackgroundLayer properties on the header file)
-(id)init{
self = [super init];
if(self != nil){
//Level1Layer
_level1GameplayLayer = [Level1Layer node];
[self addChild:_level1GameplayLayer z:0];
//Hud Layer
_hudLayer = [HUDLayer node];
[self addChild:_hudLayer z:1];
}
return self;
}
-Which holds these 2 layers
BackgroundLayer.m & .h && HUDLayer.m & .h
Everytime I click the screen I get a Log notice like this "Touched Screen"(called on backgroundlayer.m) which is followed by a function which is implemented on HUDLayer.m & .h
I call it like this:
[_hud getAmmo:self.ammoLeft magsLeft:self.magsLeft];
_hud is stated on the Scene.m like this:(and its imported on backgroundlayer.m)
HUDLayer *hudLayer = [HUDLayer node];
[self addChild:hudLayer z:1];
background is z:0.
Also BackgroundLayer.m has the property under #interface:
(I realized this is nil because its not initialized, How do I initialize this???)
#property (strong) HUDLayer *hud;
Between the call of getAmmo: I make 3 CLOGS, one BEFORE "We're about to getAmmo:"
one INSIDE the function on HUDLayer.m that calls "Inside getAmmo:"
and one AFTER "We gotTheAmmo:"
BackgroundLayer.m:
CCLOG(#"We're about to getAmmo");
_hud getAmmo:self.ammoLeft magsLeft:self.magsLeft];
CCLOG(#"We got the ammo:%d, mags:%d",self.ammoLeft,self.magsLeft);
HUDLayer.m:
-(void)getAmmo:(int)ammo magsLeft:(int)magsLeft
{
CCLOG(#"We did this");
hudMagsLeft=magsLeft;
hudAmmoLeft = ammo;
CCLOG(#"HUD MAGS: %d, AMMO:%d", hudMagsLeft,hudAmmoLeft);
}
Im only getting the one before and the one after, there's no warnings on the way the function is being called but for some reason it isn't being called. There's no if statements or anything..what is it Im doing wrong???
So to make the question more simple, how do I access properties/functions from other classes?
Thank you for your time, have a good one.
On the scene.h I added this function:
-(id)initWithHUD:(HUDLayer *)hud;
Then on the scene.m I made this:
_backgroundLayer = [[[BackgroundLayer alloc] initWithHUD:_hudLayer] autorelease];
on Backgroundlayer.m I changed regular init with
-(id)initWithHUD:(HUDLayer *)hud{
:D
I've created a custom class which is a subclass of CCLayer and trying to use it for CCScrollLayer
The way I do it is:
//Store the my layers to an NSMutableArray
for (AACustomClassLayer *cardLayer in levels) {
[layers addObject:cardLayer];
}
Under the hood of CCScrollLayer it crashes at:
- (void) updatePages
{
// Loop through the array and add the screens if needed.
int i = 0;
for (CCLayer *l in layers_)
{
l.anchorPoint = ccp(0,0);
l.contentSize = [CCDirector sharedDirector].winSize;
l.position = ccp( (i * (self.contentSize.width - self.pagesWidthOffset)), 0 );
if (!l.parent)
[self addChild:l];
i++;
}
}
The implementation for the AACustomClassLayer class (subclass of CCLayer) looks like:
-(id)initWithChapter:(AALevel *)level {
self = [super init];
if (self) {
self.isTouchEnabled = YES;
//Here I'm adding the CCSprite to my layer
}
return self;
}
UPDATE:
Crash log
2012-04-20 14:12:12.344 [15780:10a03] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFDictionary setAnchorPoint:]: unrecognized selector sent to instance 0x884ab40'
*** First throw call stack:
(0x1a75022 0x200fcd6 0x1a76cbd 0x19dbed0 0x19dbcb2 0xd013f 0xcfe2b 0x102370 0x44c15 0xbe45f 0x8a94be 0x8aa274 0x8b9183 0x8b9c38 0x8ad634 0x282def5 0x1a49195 0x19adff2 0x19ac8da 0x19abd84 0x19abc9b 0x8a9c65 0x8ab626 0xbda06 0x22e5)
terminate called throwing an exception
I've found it!
for (AACustomClassLayer *cardLayer in levels) {
cardLayer = [[AACustomClassLayer node] autorelease];
[layers addObject:cardLayer];
}
You should add a conditional check in your for loop that determines if the object you are getting from enumeration is in fact a CCLayer. Your crash log states that the anchorPoint setter was not available on some object, presumably on an object in your layers_ array since that is the code you have posted that deals with anchorPoints.
Enumeration is convenient, but you are casing all objects to CCLayer when it is possible that one of them is not. I don't know where you are adding objects to layers_ but is it possible you are adding an object that is not actually a CCLayer ?
I'm just learning how to use the C4 framework and trying to add gestures to a shape, but I can't seem to figure out how to get them to do anything. The following method creates an error, when I try to change the position of a button after it is tapped.
[buttonA addGesture:TAP name:#"tapGesture" action:#"setPosition"];
This is the error I get: * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[MyButton setPosition]: unrecognized selector sent to instance 0x7661b60'
I'm guessing that the reason you're getting the error is because the setPosition method is because you're trying to run the setPosition method directly on a C4Shape object. Natively, C4Shapes don't have this method.
In C4, all objects can have gestures attached to them, but in order run any custom code when you trigger a gesture on an object you should first subclass C4Shape and write a special method to handle the behaviour you want to see.
For example, I would create a MyShape class like this:
#interface MyShape : C4Shape
-(void)setNewPosition;
#end
#implementation MyShape
-(void)setNewPosition {
//will set the center of the shape to a new random point
self.center = CGPointMake([C4Math randomInt:768], [C4Math randomInt:1024]);
}
#end
Then, in my C4WorkSpace:
#import "C4WorkSpace.h"
#import "MyShape.h"
#implementation C4WorkSpace {
MyShape *newShape;
}
-(void)setup {
newShape = [MyShape new];
[newShape ellipse:CGRectMake(100, 100, 200, 200)];
[newShape addGesture:TAP name:#"tapGesture" action:#"setNewPosition"];
[self.canvas addShape:newShape];
}
#end
This should register a tap gesture with your new subclassed shape, and run its setNewPosition method when the gesture is triggered.
In order for the gesture to "send" the action you are trying to accomplish, you need to have a method named "setPositon" for the class "myButton". Do you have this method invoked in your code?