Cannot add CCNode to Scene - objective-c

I have the IntroScene, and I wanna add a node, but it doesn't seem to work. Here are two different ways I tried doing it, and BOTH failed.
First way, failed:
in hearts2.h
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#interface Hearts2 : CCNode {
}
#end
in hearts2.m
#import "Hearts2.h"
#implementation Hearts2
#end
in IntroLayer.m
- (id)init
{
// Apple recommend assigning self with supers return value
self = [super init];
if (!self) return(nil);
heart2 *heart;
[self addChild:heart z:2];
// done
return self;
}
I didn't expect that to work (actually I was desperate and tried it that way as the second way just to see if it would work). The actual first attempt I tried to do was this, and it also Failed:
in hearts1.h
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#interface Hearts1 : CCNode
+ (Hearts1 *)node;
- (id)init;
-(void)selfAnimate;
#end
in hearts1.m
#import "Hearts1.h"
#implementation Hearts1 {
}
+ (Hearts1 *)node
{
return [[self alloc] init];
}
- (id)init
{
self = [super init];
if (!self) return(nil);
return self;
}
- (void)dealloc
{
}
- (void)onEnter
{
[super onEnter];
}
- (void)onExit
{
// always call super onExit last
[super onExit];
}
- (void)selfAnimate
{
}
#end
in IntroLayer.m
- (id)init
{
// Apple recommend assigning self with supers return value
self = [super init];
if (!self) return(nil);
heart1 *heart;
[self addChild:heart z:2];
// done
return self;
}
Please, I would do anything if someone could help me figure this out thanks everyone very much. I always get the SigABRT so I have no idea what is going wrong. I'm sure I'm just stupid and don't know how to code and missing something simple.

heart2 *heart;
You named your class Hearts2 so use the exact same name, including uppercase.
Secondly you created a variable but this will be nil. If you aren't using ARC (which you should) this will create an uninitialized object.
This will create an instance of Hearts2, assign it to the local var heart and add it as a child:
Hearts2 *heart = [Hearts2 node];
[self addChild:heart z:2];

Related

How to swizzle initialization method?

I have one class MyOldController with init method
-(instancetype) initWithMyController: (MyController *) myController {
if((self = [self init])) {
_myController = myController;
}
return self;
}
I want swizzle this initialization method to another and this my swizzle code
#implementation MyOldController(Swizzle)
+ (void)load {
[MyOldController swizzleMethods];
}
+ (void)swizzleMethods {
method_exchangeImplementations(class_getInstanceMethod(self, #selector(initWithMyController)), class_getInstanceMethod(self, #selector(swizzle_ initWithMyController)));
}
I try write this
-(instancetype) swizzle_initWithMyController: (MyController *) myController {
if((self = [self init])) {
_myController = myController;
}
return self;
}
But it drops error
Then I renamed init method to this and updated (void)swizzleMethods
-(instancetype) initWithMyController_swizzle: (MyController *) myController {
if((self = [self init])) {
_myController = myController;
}
return self;
}
Error message disappeared but swizzle doesn't works. It just calls old initialization method, not my new.
Which point i missed? Is swizzling of initialization method have some special way to do it?
(Starting with the required caveat: this is incredibly dangerous and should never be used in production code. Swizzling initializers is particularly dangerous given designated initializer chaining, and should definitely never be done for anything but exploration and debugging without first confirming the implementation of the swizzled initializer. OK, got that out of the way.)
I can't reproduce your issue. And initializer should always start with with init, so your second approach is correct. I suspect you've just made a small mistake, perhaps in your #selector (which has a typo in your question, which suggests maybe there's a mistake in your actual code). Here is code that does what you're describing.
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#interface MyOldController: NSObject
- (instancetype)initWithInt:(NSInteger)x
#end
#implementation MyOldController
- (instancetype)initWithInt:(NSInteger)x
{
self = [super init];
if (self) {
NSLog(#"init");
}
return self;
}
#end
#implementation MyOldController(Swizzle)
+ (void)load {
[MyOldController swizzleMethods];
}
+ (void)swizzleMethods {
method_exchangeImplementations(class_getInstanceMethod(self, #selector(initWithInt:)), class_getInstanceMethod(self, #selector(initWithInt_swizzle:)));
}
- (instancetype)initWithInt_swizzle:(NSInteger)x
{
self = [super init];
if (self) {
NSLog(#"init_swizzle");
}
return self;
}
#end
int main(int argc, const char * argv[]) {
#autoreleasepool {
MyOldController *controller = [[MyOldController alloc] initWithInt:1];
NSLog(#"%#", controller);
}
return 0;
}
This prints, as expected:
2018-06-21 12:23:14.431936-0400 test[30981:401466] init_swizzle
2018-06-21 12:23:14.432172-0400 test[30981:401466] <MyOldController: 0x10051ee10>

Should I "Pull Up" Refactor

I have some very small classes that I feel should be "pulled up" but the methods are so small I'm not sure. For example, the only thing that's meaningfully different is the body of the buildFromJSON: selector.
I acknowledge that this is similar to:
Pull-up refactoring, Objective-C
but I feel my question is specific to refactoring very small classes/methods.
Also, not sure it relates to my particular code example, but I'm wondering if a child class says it conforms to a protocol, whether it's enough that it's parent actually supply the implementation of required selector(s)?
#implementation AsyncFoo
-(void)dealloc {
[clientDelegate release];
[super dealloc];
}
- (id)initWithDelegate: (id <ServiceClientProtocol>) delegate {
if((self = [super init])) {
clientDelegate = [delegate retain];
}
return self;
}
- (void)buildFromJSON:(NSString*)jsonResponseString {
[clientDelegate serviceComplete:[RestAdapter buildFooArray: jsonResponseString]];
}
#end
#implementation AsyncBar
-(void)dealloc {
[clientDelegate release];
[super dealloc];
}
- (id)initWithDelegate: (id <ServiceClientProtocol>) delegate {
if((self = [super init])) {
clientDelegate = [delegate retain];
}
return self;
}
- (void)buildFromJSON:(NSString*)jsonResponseString {
[clientDelegate serviceComplete:[RestAdapter buildBarArray:jsonResponseString]];
}
#end
Answers including code example would be great.
EDIT: Post accepted answer I'd like to add that since I was able to subclass, the derived classes did not need to declare that they conformed to protocol:
#interface Async : NSObject <ModelBuilderProtocol> {
id <ServiceClientProtocol> clientDelegate;
}
- (void)buildFromJSON:(NSString*)jsonResponseString;
#end
#interface AsyncArtistById : Async
#end
You don't normally retain your delegates as this can cause a retain cycle.
Knowing what I know from looking at your example I would probably implement like this:
The super class
// Async.h
#interface Async : NSObject
#property (nonatomic, assign) id<ServiceClientProtocol> delegate;
- (void)buildFromJSON:(NSString *)jsonResponseString;
#end
// Async.m
#implementation Async
#synthesize delegate = _delegate;
- (id)initWithDelegate:(id<ServiceClientProtocol>)delegate
{
self = [super init];
if(self) {
_delegate = delegate;
}
return self;
}
- (void)buildFromJSON:(NSString *)jsonResponseString
{
// This will ensure that we over ride this method in a sub class
[NSException raise:NSInternalInconsistencyException
format:#"You must override %# in a subclass", NSStringFromSelector(_cmd)];
}
#end
Concrete subclass AsyncFoo
// AsyncFoo.h
#interface AsyncFoo : Async
#end
// AsyncFoo.m
#implementation AsyncFoo
- (void)buildFromJSON:(NSString *)jsonResponseString
{
[self.delegate serviceComplete:[RestAdapter buildFooArray: jsonResponseString]];
}
#end
Concrete subclass AsyncBar
// AsyncBar.h
#interface AsyncBar : Async
#end
// AsyncBar.m
#implementation AsyncBar
- (void)buildFromJSON:(NSString *)jsonResponseString {
[self.delegate serviceComplete:[RestAdapter buildBarArray:jsonResponseString]];
}
#end

How to I initialize a class with an interface button clicked? [Objective - C]

I am having a problem with figuring out how to initialize a class with button clicked. The code is listed below the line I have a problem with has "HELP NEEDED HERE" comment above it.
//
// Controller.m
//
#import "Controller.h"
#implementation Controller
- (id)init {
self = [super init];
if(self){
numberTotal = 0;
//HELP NEEDED HERE
[self btnScore_Clicked:(id)sender];
}
return self;}
- (IBAction) btnScore_Clicked:(id)sender {
numberTotal += 1;
NSLog(#"Number Total: %d",numberTotal);
}
- (void)dealloc {
[super dealloc];
}
#end
//
// Controller.h
//
#import <UIKit/UIKit.h>
#interface Controller : UIViewController {
NSInteger numberTotal;
}
- (IBAction) btnScore_Clicked:(id)sender;
#end
Thanks!
Just replace
[self btnScore_Clicked:(id)sender];
with
[self btnScore_Clicked:self];
inside your -init implementation since you shouldn’t list argument types when sending a message to an object. Also, in that case, the sender of the btnScore_Clicked: action is the object itself, hence the sender parameter is self.
Furthermore,
numberTotal = 0;
is not necessary since all instance variables are zeroed out when a new instance is created.

View of custom class

I have the following class:
#interface Gamer {
...
}
+(id) CreatePlayer;
#end
#implementation Gamer
+(id) CreatePlayer
{
return [[[self alloc] init]autorelease];
}
#end
I need to use the Gamer in an another class as instance variable.
For example like this:
#interface Layer{
Gamer * mCenterGamer;
}
#end
#implementation
-(void) init{
mCenterGamer = [Gamer CreatePlayer];
}
-(void) exampleFuncForUseGamer{
[mCenterGamer ...]// some methods of the Gamer class
}
#end
Is it correct? (I think autorelease freed the mCenterGamer after exiting from the init function)
You need to retain mCenterGamer (and make sure to release it in the Layer's -dealloc method). Also, -init needs id as its return type:
- (id)init {
if (self = [super init])
mCenterGamer = [[Gamer CreatePlayer] retain];
return self;
}
- (void)dealloc {
[mCenterGamer release];
[super dealloc];
}
Your -exampleFuncForUseGamer should be fine, depending on what you're trying to do there.

Objective-C :: using a method to change an object

I have a class called "CardSet", containing an NSMutableArray* cardSet to hold "cards", which I extend to make "DeckCards". I'd like "CardSet" to have a method called "(void)addCard:(Card*)" (and similarly a method "removeCard"). I'd like "addCard" to some how have access to and set cardSet. Even better I'd like to use the "addCard" method to initialise cardSet. The class file "CardSet.h" reads:
#import < Cocoa/Cocoa.h >
#import < Card.h >
#interface CardSet : NSObject {
NSMutableArray* cardSet;
}
-(id)init;
-(NSMutableArray*)getCardSet;
-(void)setCardSet:(NSMutableArray *)new_cardset;
-(Card*)getCard:(NSInteger) index;
**-(void)addCard:(Card*) new_card;**
-(void)removeCard:(Card*) old_card;
-(void)dealloc;
#property (readwrite, retain, getter=getCardSet, setter=setCardSet) NSMutableArray* cardSet;
#end
and the method file reads:
#import "CardSet.h"
#implementation CardSet
-(id)init{
if( self = [super init] ){} //will add initialisations here later
return self;
}
-(NSMutableArray*)getCardSet{
return cardSet;
}
-(void)setCardSet:(NSMutableArray *)new_cardSet{
cardSet = new_cardSet;
}
-(Card*)getCard:(NSInteger)index{
return [cardSet objectAtIndex:index];
}
**-(void)addCard:(Card *)new_card{
[cardSet addObject:new_card];
}**
-(void)removeCard:(Card *)old_card{
[cardSet removeObject:old_card];
}
-(void)dealloc{
[cardSet release];
[super dealloc];
}
#synthesize cardSet;
#end
This compiles just fine. I'd like to initialise a "DeckCards" instance using its "addCard" method 52 times. When I call addCard 52 times in a DeckCards setter method, and ask for the size of its "cardSet", I'm returned 0.
This appears to be a scope or privileges problem? Can the "addCard" method have any setter privileges? Must a setter argument be the same as the return and respective member type?
[I can work around the above by creating an NSMutableArray object "deck_cards_temp" outside of "DeckCard", add 52 cards to this, and pass it to set the member of my "DeckCards" instance via the setter inherited from "CardSet". This is not very satisfactory!]
What do you advise? Many thanks in advance for your help and patience.
You are never actually creating the cardSet object. You should be creating it in your -init method:
-(id)init
{
if( self = [super init] )
{
cardSet = [[NSMutableArray alloc] init];
}
return self;
}
Because you never actually create the array, all the calls to -addCard: are being sent to a nil object.
When you pass in an array to -setCardSet:, you are passing in an initialized array so the array is no longer nil and the -addCard: calls work fine.
CardSet.h
#import <Cocoa/Cocoa.h>
// For know we just need to know there is a class named "Card" being used but implemented later
#class Card;
#interface CardSet : NSObject {
NSMutableArray *cardSet;
}
// Here are the methods according to "correct" naming conventions
- (Card *)cardAtIndex:(NSInteger)index;
- (void)addCard:(Card *)card;
- (void)removeCard:(Card *)card;
// This will help us and forget about writing the setter/getter
#property (nonatomic, retain) NSMutableArray *cardSet;
#end
CardSet.m
#import "CardSet.h"
// Now we tell the compiler what "Card" is and what methods etc. it has
#import "Card.h"
#implementation CardSet
#synthesize cardSet;
- (id)init {
if (self = [super init]) {
// If we don't create the cardSet, how are we able to work with it!?
NSMutableArray *anArray = [[NSMutableArray alloc] init];
self.cardSet = anArray;
[anArray release];
}
return self;
}
- (Card *)cardAtIndex:(NSInteger)index {
return [cardSet objectAtIndex:index];
}
- (void)addCard:(Card *)card {
[cardSet addObject:card];
}
- (void)removeCard:(Card *)card {
[cardSet removeObject:card];
}
- (void)dealloc {
[cardSet release];
[super dealloc];
}
#end
As Abizern already noted: Naming the array the same as your class is a bad thing.
I would shorten that init method:
- (id)init {
if (self = [super init]) {
// If we don't create the cardSet, how are we able to work with it!?
self.cardSet = [NSMutableArray array];
}
return self;
}