How to pass 2 parameters with a self method Cocos2d - objective-c

This is probably a noobish question that has been answered before, but I can't seem to find a solution online (Google is not being friendly). My question is, relating to Cocos2d, how would I pass 2 parameters using a self method.
An Example of my Code
-(void)Random {
[self AiCharacter:theEvilOne];
[self AiCharacter:theEvilTwo];
}
-(void)AiCharacter(CCSprite*)EvilCharacter {
//stuff
}
But I want to do something like the following
-(void)Random {
num = 1
[self AiCharacter:theEvilOne, Num];
num = 2
[self AiCharacter:theEvilTwo, Num];
}
-(void)AiCharacter:(CCSprite*)EvilCharacter (NSInteger*)num { //This line is what seems to be incorrectly formatted/syntactically incorrect.
//stuff
}
To give you some more info into what I am doing is that I have an multi-dimensional array of values relating to my separate AI Characters and have the num value to differentiate the rows pertaining to each sprite.

The ":" defines a parameter in a method signature. This is how to write it :
-(void)AiCharacter:(CCSprite*)EvilCharacter num:(NSInteger*)num {
}
You can check this post for more information How do I pass multiple parameters in Objective-C?

Try this
-(void)Random {
num = 1
[self AiCharacter:theEvilOne: Num];
num = 2
[self AiCharacter:theEvilTwo: Num];
}
-(void)AiCharacter:(CCSprite*)EvilCharacter : (NSInteger*)num {
//This line is what seems to be incorrectly formatted/syntactically incorrect.
//stuff
}

See the method calling way carefully especially the colons and the parameters... or else you will encounter a crash
-(void)Random {
num = 1
[self AiCharacter:theEvilOne number:num];
num = 2
[self AiCharacter:theEvilTwo number:num];
}
-(void)AiCharacter:(CCSprite*)EvilCharacter number:(NSInteger)num {
}

Try this
-(void)Random {
CGPoint point=ccp(1.0,2.0);
[self AiCharacter:theEvilOne: point];
}
-(void)AiCharacter:(CCSprite*)EvilCharacter :(CGPoint)point {
float x=point.x;
float y=point.y;
}

Related

Objective-C passing parameters in void method

How would I go about passing parameters when calling a void method? I understand that you can do something like this:
-(void)viewDidLoad {
[self callMethod];
}
-(void)callMethod {
//stuff here
}
But how would I pass a parameter, such as an NSString, to the callMethod method?
Here is an example with an integer parameter.
-(void)viewDidLoad {
[self callMethodWithCount:10];
}
-(void)callMethodWithCount:(NSInteger)count {
//stuff here
}
In objective-c the parameters are included within the method name. You can add multiple parameters like this:
-(void)viewDidLoad {
[self callMethodWithCount:10 animated:YES];
}
-(void)callMethodWithCount:(NSInteger)count animated:(BOOL)animate{
//stuff here
}
It seems you may be misunderstanding what the void in the beginning of the method means. It's the return value. For a void method, nothing is returned from calling the method. If you wanted to return a value from your method you would do it like this:
-(void)viewDidLoad {
int myInt = [self callMethodWithCount:10 animated:YES];
}
-(int)callMethodWithCount:(NSInteger)count animated:(BOOL)animate{
return 10;
}
You define your method to return an int (in this example it always returns 10.) Then you can set an integer to the value returned by calling the method.
- (void)callMethod:(NSString *)string
{
}
Where string is your parameter so you would call
NSString *myString = #"your string here......";
[self callMethod:myString];

Cocoa binding: NSTextField with empty string for zero value

I have NSTextField with placeholder. And it's binded to some integer property. So I want to display empty text in the field (with placeholder shown) when binded integer is zero.
Is it possible to do it?
(Update)
I discovered that this can be done through NSNumberFormatter - it has —(void) setZeroSymbol: (NSString*) string method. Not tried yet this in practice...
You could use an NSValueTransformer.
(Just in case)Create a new class, subclass from NSValueTransformer. In the implementation, add something like this:
+(Class)transformedValueClass {
return [NSString class];
}
-(id)transformedValue:(id)value {
if (value == nil) {
return nil;
} else {
if ([value integerValue] == 0) {
return #"";
} else {
return [NSString stringWithFormat:#"%d", [value stringValue]];
}
}
}
In Interface Builder, select your field, go to the bindings tab, and in the Value Transformer drop down, either select or type in your class name you made. This should prevent you from having to worry about modifying it elsewhere. I'm not 100% positive about it showing the placeholder (I don't have a Mac available right now).
EDIT:
I can confirm that this does indeed work. Here is a link to a github project I made to show how to use it: https://github.com/macandyp/ZeroTransformer
check the integer value before binding, if you are binding at runtime. Try
int i;
if (i == 0)
{
txt.placeholder = #"text";
}
else
{
[txt setStringValue:[NSString stringWithFormat:#"%d",i]];
}
You can not do conditional binding.
You need to create another property that will hold the value based on condition and use that property and bind to textfield.
I am using bindedString and bindedInteger. bindedString is bound to text field.
Whenever some action is performed it is updated.
- (id)init{
self = [super init];
if (self) {
self.bindedString=#"place holder string";
}
return self;
}
- (IBAction)button:(id)sender {
if (self.bindedInteger==0) {
self.bindedString=#"place holder string";
}
else{
self.bindedString=[NSString stringWithFormat:#"%ld",self.bindedInteger];
}
}

Getting two images to appear in random sequence iOS

I am new to the community, so let me know if my question is unclear. I am trying to make a choice reaction exercise on the iPAD. There are two images that should appear in random sequence on the left and right of the screen, and the user will respond by tapping a button that corresponds to the position of the appeared image. Here's the problem, I tried to get the two images to appear at random order using the following way:
- (void) viewDidAppear:(BOOL)animated
{
for(int n = 1; n <= 20; n = n + 1)
{
int r = arc4random() % 2;
NSLog(#"%i", r);
if(r==1)
{
[self greenCircleAppear:nil finished:nil context: nil];
}
else
{
[self redCircleAppear:nil finished:nil context: nil];
}
}
}
However, 20 random numbers get generated while only 1 set of animation is run. Is there a way to let the animation finish running in each loop before the next loop begins? Any help is appreciated, thanks in advance!
When you say "only one set of animation is run" I'm assuming that means greenCircleAppear and redCircleAppear begin the sequence of images appearing and the user pressing a button. If that's the case, I'd recommend not using a for loop in viewDidAppear but instead have viewDidAppear initialize the current state and call a method that presents the next animation. When the animation is finished, have it call the method that presents the next animation. Something along these lines:
Add this to the interface:
#interface ViewController ()
#property NSInteger currentIteration;
#end
This is in the implementation:
- (void)viewDidAppear:(BOOL)animated {
self.currentIteration = 0;
[self showNextAnimation];
}
- (void)greenCircleAppear:(id)arg1 finished:(id)arg2 context:(id)arg3 {
//perform animation
NSLog(#"green");
[self showNextAnimation];
}
- (void)redCircleAppear:(id)arg1 finished:(id)arg2 context:(id)arg3 {
//perform animation
NSLog(#"red");
[self showNextAnimation];
}
- (void)showNextAnimation {
self.currentIteration = self.currentIteration + 1;
if (self.currentIteration <= 20) { //you should replace '20' with a constant
int r = arc4random() % 2;
NSLog(#"%i", r);
if(r==1)
{
[self greenCircleAppear:nil finished:nil context: nil];
}
else
{
[self redCircleAppear:nil finished:nil context: nil];
}
}
else {
//do what needs to be done after the last animation
}
}

Can Objective-C switch on NSString?

Is there a more intelligent way to rewrite this?
if ([cardName isEqualToString:#"Six"]) {
[self setValue:6];
} else if ([cardName isEqualToString:#"Seven"]) {
[self setValue:7];
} else if ([cardName isEqualToString:#"Eight"]) {
[self setValue:8];
} else if ([cardName isEqualToString:#"Nine"]) {
[self setValue:9];
}
Unfortunately they cannot. This is one of the best and most sought after utilizations of switch statements, so hopefully they hop on the (now) Java (and others) bandwagon!
If you are doing card names, perhaps assign each card object an integer value and switch on that. Or perhaps an enum, which is considered as a number and can therefore be switched upon.
e.g.
typedef enum{
Ace, Two, Three, Four, Five ... Jack, Queen, King
} CardType;
Done this way, Ace would be be equal to case 0, Two as case 1, etc.
You could set up a dictionary of blocks, like this:
NSString *lookup = #"Hearts"; // The value you want to switch on
typedef void (^CaseBlock)();
// Squint and this looks like a proper switch!
NSDictionary *d = #{
#"Diamonds":
^{
NSLog(#"Riches!");
},
#"Hearts":
^{
self.hearts++;
NSLog(#"Hearts!");
},
#"Clubs":
^{
NSLog(#"Late night coding > late night dancing");
},
#"Spades":
^{
NSLog(#"I'm digging it");
}
};
((CaseBlock)d[lookup])(); // invoke the correct block of code
To have a 'default' section, replace the last line with:
CaseBlock c = d[lookup];
if (c) c(); else { NSLog(#"Joker"); }
Hopefully Apple will teach 'switch' a few new tricks.
For me, a nice easy way:
NSString *theString = #"item3"; // The one we want to switch on
NSArray *items = #[#"item1", #"item2", #"item3"];
int item = [items indexOfObject:theString];
switch (item) {
case 0:
// Item 1
break;
case 1:
// Item 2
break;
case 2:
// Item 3
break;
default:
break;
}
Unfortunately, switch statements can only be used on primitive types. You do have a few options using collections, though.
Probably the best option would be to store each value as an entry in an NSDictionary.
NSDictionary *stringToNumber = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:6],#"Six",
[NSNumber numberWithInt:7],#"Seven",
[NSNumber numberWithInt:8],#"Eight",
[NSNumber numberWithInt:9],#"Nine",
nil];
NSNumber *number = [stringToNumber objectForKey:cardName];
if(number) [self setValue:[number intValue]];
A bit late but for anyone in the future I was able to get this to work for me
#define CASE(str) if ([__s__ isEqualToString:(str)])
#define SWITCH(s) for (NSString *__s__ = (s); ; )
#define DEFAULT
Here is the more intelligent way to write that. It's to use an NSNumberFormatter in the "spell-out style":
NSString *cardName = ...;
NSNumberFormatter *nf = [[NSNumberFormatter alloc] init];
[nf setNumberStyle:NSNumberFormatterSpellOutStyle];
NSNumber *n = [nf numberFromString:[cardName lowercaseString]];
[self setValue:[n intValue]];
[nf release];
Note that the number formatter wants the string to be lowercased, so we have to do that ourselves before passing it in to the formatter.
There are other ways to do that, but switch isn't one of them.
If you only have a few strings, as in your example, the code you have is fine. If you have many cases, you could store the strings as keys in a dictionary and look up the corresponding value:
NSDictionary *cases = #{#"Six" : #6,
#"Seven" : #7,
//...
};
NSNumber *value = [cases objectForKey:cardName];
if (value != nil) {
[self setValue:[value intValue]];
}
BY FAR.. my FAVORITE "ObjC Add-On" is ObjectMatcher
objswitch(someObject)
objcase(#"one") { // Nesting works.
objswitch(#"b")
objcase(#"a") printf("one/a");
objcase(#"b") printf("one/b");
endswitch // Any code can go here, including break/continue/return.
}
objcase(#"two") printf("It's TWO."); // Can omit braces.
objcase(#"three", // Can have multiple values in one case.
nil, // nil can be a "case" value.
[self self], // "Case" values don't have to be constants.
#"tres", #"trois") { printf("It's a THREE."); }
defaultcase printf("None of the above."); // Optional default must be at end.
endswitch
AND it works with non-strings, TOO... in loops, even!
for (id ifNumericWhatIsIt in #[#99, #0, #"shnitzel"])
objswitch(ifNumericWhatIsIt)
objkind(NSNumber) printf("It's a NUMBER.... ");
objswitch([ifNumericWhatIsIt stringValue])
objcase(#"3") printf("It's THREE.\n");
objcase(#"99") printf("It's NINETY-NINE.\n");
defaultcase printf("some other Number.\n");
endswitch
defaultcase printf("It's something else entirely.\n");
endswitch
It's a NUMBER.... It's NINETY-NINE.
It's a NUMBER.... some other Number.
It's something else entirely.
Best of all, there are SO few {...}'s, :'s, and ()'s
Objective-c is no different from c in this aspect, it can only switch on what c can (and the preproc def's like NSInteger, NSUInteger, since they ultimately are just typedef'd to an integral type).
Wikipedia:
c syntax:
The switch statement causes control to be transferred to one of several statements depending on the value of an expression, which must have integral type.
Integral Types:
In computer science, an integer is a datum of integral data type, a
data type which represents some finite subset of the mathematical
integers. Integral data types may be of different sizes and may or may
not be allowed to contain negative values.
I'm kind of late to the party, but to answer the question as stated, there's a more intelligent way:
NSInteger index = [#[#"Six", #"Seven", #"Eight", #"Nine"] indexOfObject:cardName];
if (index != NSNotFound) [self setValue: index + 6];
Note that indexOfObject will look for the match using isEqual:, exactly as in the question.
Building on #Graham Perks idea posted earlier, designed a simple class to make switching on strings fairly simple and clean.
#interface Switcher : NSObject
+ (void)switchOnString:(NSString *)tString
using:(NSDictionary<NSString *, CaseBlock> *)tCases
withDefault:(CaseBlock)tDefaultBlock;
#end
#implementation Switcher
+ (void)switchOnString:(NSString *)tString
using:(NSDictionary<NSString *, CaseBlock> *)tCases
withDefault:(CaseBlock)tDefaultBlock
{
CaseBlock blockToExecute = tCases[tString];
if (blockToExecute) {
blockToExecute();
} else {
tDefaultBlock();
}
}
#end
You would use it like this:
[Switcher switchOnString:someString
using:#{
#"Spades":
^{
NSLog(#"Spades block");
},
#"Hearts":
^{
NSLog(#"Hearts block");
},
#"Clubs":
^{
NSLog(#"Clubs block");
},
#"Diamonds":
^{
NSLog(#"Diamonds block");
}
} withDefault:
^{
NSLog(#"Default block");
}
];
The correct block will execute according to the string.
Gist for this solution
You can use macros approach to achieve it:
#define CASE(str) if ([__s__ isEqualToString:(str)])
#define SWITCH(s) for (NSString *__s__ = (s); ; )
#define DEFAULT
SWITCH (string) {
CASE (#"TestString") {
break;
}
CASE (#"YetAnotherString") {
break;
}
CASE (#"Test") {
break;
}
DEFAULT {
break;
}
}
I can't Comment on cris's answer on #Cris answer but i would like to say that:
There is an LIMITATION for #cris's method:
typedef enum will not take alphanumeric values
typedef enum
{
12Ace, 23Two, 23Three, 23Four, F22ive ... Jack, Queen, King
} CardType;
So here is another One:
Link Stack over flow Go to this user answer "user1717750"
typedef enum
{
Six,
Seven,
Eight
} cardName;
- (void) switchcardName:(NSString *) param {
switch([[cases objectForKey:param] intValue]) {
case Six:
NSLog(#"Six");
break;
case Seven:
NSLog(#"Seven");
break;
case Eight:
NSLog(#"Eight");
break;
default:
NSLog(#"Default");
break;
}
}
Enjoy Coding.....

'If' conditional works with NSLog but not without? Objective-C

I hope this question is some what self explanatory.
This works, returns YES and NO: note the NSLog()'s
- (BOOL)dateTestCourse:(NSDictionary *)listing {
BOOL result = ([self exammpleTest] == 0) ? YES : NO;
if (result) {
NSLog(#"Passes Test");
return YES;
}
NSLog(#"Failed Test");
return NO;
}
But below always return YES? Only difference is no NSLog();
- (BOOL)dateTestCourse:(NSDictionary *)listing {
BOOL result = ([self exammpleTest] == 0) ? YES : NO;
if (result) {
// NSLog(#"Passes Test");
return YES;
}
// NSLog(#"Failed Test");
return NO;
}
Is this something to do with C? I have no idea? I might expect it always to return NO (if I shouldn't be breaking in the conditional), but surely that would return YES.
I know I should be returning result in the above examples, but I'm curious to know why.
These two blocks of code should be running the same. Are you perhaps doing a find/replace all on NSLog? That could be causing issues elsewhere, say with the exammpleTest(sic) method.
Also, the ternary operator on the second line is redundant, consider reducing that line to:
BOOL result = ([self exammpleTest] == 0);