Do [sprite stopActionByTag: kTag]; work differently for CCAction and CCSequence? - cocoa-touch

//prog 1
-(void)gameLogic:(ccTime)dt
{
id actionMove = [CCMoveTo actionWithDuration:1.0 position:ccp(windowSize.width/2-400, actualY)];
[actionMove setTag:6];
[self schedule:#selector(update:)];
[hitBullet runAction:actionMove];
}
-(void)update:(ccTime)dt
{
if ( (CGRectIntersectsRect(hitRect, playerRect)) )
{
[[[self getActionByTag:6] retain] autorelease];
[hitBullet stopActionByTag: 6];
}
}
//prog 2
-(void)gameLogic:(ccTime)dt
{
id actionMove = [CCMoveTo actionWithDuration:1.0 position:ccp(windowSize.width/2-400, actualY)];
id hitBulletAction = [CCSequence actionWithDuration:(intervalforEnemyshoot)];
id hitBulletSeq = [CCSequence actions: hitBulletAction, actionMove, nil];
[hitBulletSeq setTag:5];
[self schedule:#selector(update:)];
[hitBullet runAction:hitBulletSeq];
}
-(void)update:(ccTime)dt
{
if ( (CGRectIntersectsRect(hitRect, playerRect)) )
{
[[[self getActionByTag:5] retain] autorelease];
[hitBullet stopActionByTag: 5];
}
}
While prog1 is working prog2 is not working ? I think the both are same. But why the two stopActions are working differently in two prog1 and prog2 ? I mean the actions are stopped in prog1 but the actions are not stopping in prog2 ?
thank You.

Srikanth, what version of cocos2d are you using?
The answer to your question is no. All actions are treated the same.
The code responsible for removing the action is the following:
// -[CCActionManager removeActionByTag:target:]
-(void) removeActionByTag:(int) aTag target:(id)target
{
NSAssert( aTag != kActionTagInvalid, #"Invalid tag");
NSAssert( target != nil, #"Target should be ! nil");
tHashElement elementTmp;
elementTmp.target = target;
tHashElement *element = ccHashSetFind(targets, CC_HASH_INT(target), &elementTmp);
if( element ) {
NSUInteger limit = element->actions->num;
for( NSUInteger i = 0; i < limit; i++) {
CCAction *a = element->actions->arr[i];
if( a.tag == aTag && [a originalTarget]==target)
return [self removeActionAtIndex:i hashElement:element];
}
// CCLOG(#"cocos2d: removeActionByTag: Action not found!");
} else {
// CCLOG(#"cocos2d: removeActionByTag: Target not found!");
}
}
What I would recommend you do is turn on Cocos2d debugging, and un-comment those two CCLog lines. That should tell you if there's a problem in there.
If that doesn't tell you anything, it may be of interest to look into the CCSequence class. Perhaps, if the sequence is being removed, it doesn't remove the actions IN the sequence itself?
All actions are treated equal, but perhaps this Sequence action should be an exception to that.

Related

Bindings does not update NSTextField

I use bindings to NSObjectController within XIB. When I set new content object of NSObjectController the only textfield value which doesn't change is the one that has first responder. Model changes without an issue.
If I don't use custom getter/setter the textfield that has firstResponder (isBeingEdited) changes without an issue.
What's wrong with my KVC, KVO?
My custom getter/setter is below pic.
PS: I don't want to make window a first responder before I change content object to make it work.
static const CGFloat MMsInOneInch = 25.4;
static const CGFloat inchesInOneMM = 0.0393700787402;
- (void)setPaperWidth:(CGFloat)paperWidth
{
[self willChange];
CGFloat newWidth = paperWidth * [self conversionKoeficientToDefaultUnitType];
if (!_isChangingPaperSize) {
if (self.paperSize == PPPaperSizeA4 && fabs(newWidth - widthSizeOfA4) > 0.001) {
[self setPaperSize:PPPaperSizeCustom];
}
if (self.paperSize == PPPaperSizeUSLetter && fabs(newWidth - widthSizeOfUSLetter) > 0.001 ) {
[self setPaperSize:PPPaperSizeCustom];
}
}
[self willChangeValueForKey:#"paperWidth"];
_paperWidth = newWidth;
[self didChangeValueForKey:#"paperWidth"];
[self didChange];
}
- (CGFloat)conversionKoeficientToDefaultUnitType
{
if ([self defaultUnitType] == [self unitType]) {
return 1;
}
if ([self defaultUnitType] == PPPrintSettingsUnitTypeMM) {
return MMsInOneInch;
}
if ([self defaultUnitType] == PPPrintSettingsUnitTypeInch) {
return inchesInOneMM;
}
return 1;
}
- (CGFloat)paperWidth
{
return _paperWidth / [self conversionKoeficientToDefaultUnitType];
}
I forgot that I use NSNumberFormatter with min/max value which where blocking NSTextField to update.

Efficient way of checking the content of every NSDictionary in NSArray

In my app I'me getting responses from the server and I have to check that I don't create duplicate objects in the NSArray which contains NSDictionaries. Now to check if the objects exists I do this:
for (int i = 0; i < appDelegate.currentUser.userSiteDetailsArray.count; i++){
NSDictionary *tmpDictionary = [appDelegate.currentUser.userSiteDetailsArray objectAtIndex:i];
if ([[tmpDictionary valueForKey:#"webpropID"] isEqualToString:tmpWebproperty.identifier]){
needToCheck = NO;
}
if (i == appDelegate.currentUser.userSiteDetailsArray.count - 1 && ![[tmpDictionary valueForKey:#"webpropID"] isEqualToString:tmpWebproperty.identifier] && needToCheck){
// It means it's the last object we've iterated through and needToCheck is still = YES;
//Doing stuff here
}
}
I set up a BOOL value because this iteration goes numerous times inside a method and I can't use return to stop it. I think there is a better way to perform this check and I would like to hear your suggestions about it.
BOOL needToCheck = YES;
for (int i = 0; i < appDelegate.currentUser.userSiteDetailsArray.count; i++){
NSDictionary *tmpDictionary = [appDelegate.currentUser.userSiteDetailsArray objectAtIndex:i];
if ([[tmpDictionary valueForKey:#"webpropID"] isEqualToString:tmpWebproperty.identifier]){
needToCheck = NO;
break;
}
}
if (needToCheck) {
//Doing stuff here
}
But, as others have said, you can maybe keep a "summary" in a separate NSSet that you check first, vs spinning through all the dictionaries.
NSDictionary *previousThing = nil;
for (NSDictionary *thing in appDelegate.currentUser.userSiteDetailsArray) {
if ([thing[#"webpropID"] isEqualToString:newWebPropertyIdentifier]) {
previousThing = thing;
break;
}
}
if (previousThing == nil) {
// no previous thing
} else {
// duplicate
}

Deleting one object at a time every 5 seconds Cocos2d

I have a problem with my cocos2d game. I am trying to delete a projectile shot by an enemy every 5 seconds (each projectile is supposed to have a lifetime of 5 seconds), but I cannot figure out how to do it. I get the error of
Assertion failure in -[CCTimer initWithTarget:selector:interval:]
Here is my code:
-(void)projectileShooting:(ccTime)dt
{
[self schedule:#selector(projectileShooting:) interval:2.5];
projcount++;
if([proj count] <= 15 ){
if(enemy1.position.y < 320){
v = ccp(player.position.x,player.position.y);
for(CCSprite *enemies in enemy){
CCSprite * projectilebullet = [CCSprite spriteWithFile:#"Projectile.png"];
[proj addObject:projectilebullet];
[self addChild:projectilebullet];
CGPoint MyVector = ccpSub(enemies.position,player.position );
MyVector = ccpNormalize(MyVector);
MyVector = ccpMult(MyVector, enemies.contentSize.width/2);
MyVector = ccpMult(MyVector,-1);
projectilebullet.position = ccpAdd(enemies.position, MyVector);
for(CCSprite *projectile in proj){
[self schedule:#selector (deleteprojectile:projectile:) interval:5];
}
}
}
}
for(CCSprite *enem2 in enemytwo)
{
if( [proj count] <= 15){
CCSprite * projectilebull = [CCSprite spriteWithFile:#"Projectile.png"];
CGPoint MyVector = ccpSub(enem2.position,player.position );
MyVector = ccpNormalize(MyVector);
MyVector = ccpMult(MyVector, enem2.contentSize.width/2+10);
MyVector = ccpMult(MyVector,-1);
projectilebull.position = ccpAdd(enem2.position, MyVector);
[self addChild:projectilebull];
[proj addObject:projectilebull];
for(CCSprite *projectile in proj){
}
}
}
}
-(void)deleteprojectile:(CCSprite *)protime:(ccTime)dt{
NSMutableArray *timepro = [[NSMutableArray alloc]init];
[timepro addObject:protime];
for(CCSprite *objecttime in timepro){
[proj removeObject:objecttime];
[self removeChild:objecttime cleanup:YES];
}
}
It's a bit of a hack but this is what I use in my program, until I find a more elegant solution. I have a method in my game layer that I call to remove a node from its parent, like so:
-(void)removeNode:(CCNode*)node {
[node removeFromParentAndCleanup:YES];
}
And when I want to schedule a node for deletion after a delay, I call it like this:
[self performSelector:#selector(removeNode:) withObject:node afterDelay:delay];
Simple, and it works.
Change argument name in your selector to protime instead of projectile. The selector must match the signature defined in you object's class definition.
Your selector was not defined properly and probably the Timer is checking if the object implements the given selector.
I did not have time to test it so thanks to #RamyAlZuhouri for confirming.

Is there a way for me to combine these 3 methods into just 1?

Basically, I have 3 delegate methods that have almost the exact same code except for 1 line in each and the parameters. I realize that I can encapsulate a lot of the code to make 3 or 4 lines of code in each method, but I'm wondering if there's a way to create just 1 method.
Also, the methods being called on tempData have the same method name as the delegate methods below, but they are actually different methods.
- (void)addElement:(NSString *)currentElement FromKeyboard:(NSString *)name {
UIView *tempView;
NSMutableArray *tempViewList;
EquationData *tempData;
if ([name isEqualToString:#"leftEqCellKeyboard"]) {
tempData = leftData;
tempViewList = leftEqViewList;
tempView = equationCell.leftView;
}
if ([name isEqualToString:#"rightEqCellKeyboard"]) {
tempData = rightData;
tempViewList = rightEqViewList;
tempView = equationCell.rightView;
}
[tempData addElement:currentElement]; // different
if ([tempViewList count] != 0)
[self clearViewsStoredIn:tempViewList];
[self setUpView:tempView fromArray:tempData.equation toArray:tempViewList];
}
- (void)changeState:(NSString *)stateName FromKeyboard:(NSString *)name {
UIView *tempView;
NSMutableArray *tempViewList;
EquationData *tempData;
if ([name isEqualToString:#"leftEqCellKeyboard"]) {
tempData = leftData;
tempViewList = leftEqViewList;
tempView = equationCell.leftView;
}
if ([name isEqualToString:#"rightEqCellKeyboard"]) {
tempData = rightData;
tempViewList = rightEqViewList;
tempView = equationCell.rightView;
}
[tempData changeState:stateName]; // different
if ([tempViewList count] != 0)
[self clearViewsStoredIn:tempViewList];
[self setUpView:tempView fromArray:tempData.equation toArray:tempViewList];
}
- (void)changeCharge:(NSString *)chargeIncrease FromKeyboard:(NSString *)name {
UIView *tempView;
NSMutableArray *tempViewList;
EquationData *tempData;
if ([name isEqualToString:#"leftEqCellKeyboard"]) {
tempData = leftData;
tempViewList = leftEqViewList;
tempView = equationCell.leftView;
}
if ([name isEqualToString:#"rightEqCellKeyboard"]) {
tempData = rightData;
tempViewList = rightEqViewList;
tempView = equationCell.rightView;
}
[tempData changeCharge:chargeIncrease]; // different
if ([tempViewList count] != 0)
[self clearViewsStoredIn:tempViewList];
[self setUpView:tempView fromArray:tempData.equation toArray:tempViewList];
}
(Perhaps you should check out http://codereview.stackexchange.com)
The "different" part is always of the form [tempData doSomethingOn:aString];, so you can parametrize with the selector "doSomethingOn:":
-(void)doSomethingOnString:(NSString*)parameter
withSelector:(SEL)selector
fromKeyboard:(NSString*)name
{
// The common parts before
[tempData performSelector:selector withObject:parameter];
// The common parts after
}
-(void)addElement:(NSString *)currentElement FromKeyboard:(NSString *)name {
[self doSomethingOnString:currentElement
withSelector:#selector(addElement:)
fromKeyboard:name];
}
// etc.
See also:
-performSelector:withObject:
The "Selector" concept in Objective-C

OCMock: Make a stub do something

I'm getting used to OCMock. Coming from a Java/JMock background I'm now looking for the ability to say [[[myMock stub] returnValueFromCustomMethod] someMockedMethod]; where returnValueFromCustomMethod is defined in the test class. I was originally thinking something along the terms of [[[myMock stub] usingSelector:#selector(myMethod:)] someMockedMethod]; but after writing I wonder if my first approach makes more sense. Either way, could someone show me if and how this can be done?
My original answer was off-track: OCMock doesn't support this! If you wanted to change OCMock to support this, you would need to do something like adding a BOOL returnValueIsFromInvocation field to OCMockRecorder, and add a method to set this up:
- (id)andReturnResultOfInvocation:(NSInvocation *)anInvocation {
returnValueIsFromInvocation = YES;
returnValueIsBoxed = NO;
returnValueShouldBeThrown = NO;
[returnValue autorelease];
returnValue = [anInvocation retain];
return self;
}
Then teach setUpReturnValue to call the invocation (changes are in bold):
- (void)setUpReturnValue:(NSInvocation *)anInvocation
{
if (returnValueIsFromInvocation) {
NSInvocation *returnValueInvocation = (NSInvocation *)returnValue;
[returnValueInvocation invoke];
void *buffer = malloc([[anInvocation methodSignature] methodReturnLength]);
[returnValueInvocation getValue:buffer];
[anInvocation setReturnValue:buffer];
free(buffer);
}
else if(returnValueShouldBeThrown)
{
#throw returnValue;
}
else if(returnValueIsBoxed)
{
if(strcmp([[anInvocation methodSignature] methodReturnType],
[(NSValue *)returnValue objCType]) != 0)
[NSException raise:NSInvalidArgumentException
format:#"Return value does not match method signature."];
void *buffer = malloc([[anInvocation methodSignature] methodReturnLength]);
[returnValue getValue:buffer];
[anInvocation setReturnValue:buffer];
free(buffer);
}
else
{
const char *returnType = [[anInvocation methodSignature] methodReturnType];
const char *returnTypeWithoutQualifiers = returnType + (strlen(returnType) - 1);
if(strcmp(returnTypeWithoutQualifiers, #encode(id)) == 0)
[anInvocation setReturnValue:&returnValue];
}
}
This change is difficult to do by introducing subclasses because you have to override the methods that return OCMockRecorders (like stub, expect and so on) but the concrete subclasses of OCMockObject (OCClassMockObject and OCProtocolMockObject) are hidden by the framework.