I have created a few sprites using a spriteclass and I have loaded them into an array. In my app, I loop over the array checking for particular conditions (position, etc.). I want to create an explosion method that I can pass one of these objects to and then using the pointer pull the position of the object on the screen and show an explosion there. I don't know how to pass the pointer/object that is in my array to the method to be used.
Here is essentially what I had in mind:
for (int i=1; i<4; i++) {
EnemySprite *currentenemy = [enemies objectAtIndex:i-1];
//Blow this guy up
[self explosion:currentenemy]
}
-(void)explosion someobject {
explosion.position = someobject.position
someobject.setHidden=YES;
}
You would write it like this for one param
// definition
-(void) explosion:(EnemySprite*) someObject
{
}
// usage
[self explosion: object];
For two params things are a bit more involved. Consider;
// definition
-(void) explosion:(EnemySprite*) someObject radius:(float)explosionRadius
{
...
if (pos < explosionRadius)
...
}
// usage
[self explosion: object radius:10.0f];
Everything before the : is used for the external name, everything after is the name internal to the function.
This is why you will often see Objective-C functions written with function names that end with the name of the first type:
-(void) explodeSprite:(EnemySprite*) sprite radius:(float)radius;
Both the sprite and radius params then appear to be "named" when the function is written;
[self explodeSprite:sprite radius:10.0f];
Why not make your object the receiver of the explosion?
for (id currentenemy in enemies)
{
[currentenemy explode];
}
Related
I want to be able to update two sets of identical buttons with one function. Also I don't want to update all the buttons, only some of them.
Can I have a function like this?:
-(void) updateFields{
updateButton1 : (Bool) x
updateButton2 : (Bool) y
updateButton3 : (Bool) z }
The implementation will look like this:
[button1_1 setEnabled:x];
[button1_2 setEnabled:x]; //called only if updateButton1 is given an argument
[button2_1 setEnabled:y];
etc...
What about passing an array of button and an array of boolean wrapped in a NSNumber?
- (void)updateButton:(NSArray *)buttons withArray:(NSArray *)enablers {
// buttons is an array of UIButton
// enablers is an array of NSNumber created from boolean value
// Security check
if(buttons.count != enabler.count) {
NSLog(#"Error: array have different dimensions");
return;
}
// Enable buttons
for(int i=0; i<buttons.count; i++) {
UIButton *button = (UIButton *)[buttons objectAtIndex:i];
BOOL enable = [[enablers objectAtIndex:i] boolValue]
[button setEnabled:enable];
}
}
This may not be possible with primitive data types unless you create objects from them and put them in NSArray or NSDictionary. Other option can be to create a custom object and pass that as argument.
- (void)selectButton:(SelectedButton *)iButton {
if (iButton.type = A) {
// Handle A
} else if (iButton.type = B) {
// Handle B
} else if (iButton.type = C) {
// Handle C
}
}
i think the syntax you're going for makes more sense as a C function
however note that in this example the parameters are NOT optional.
void updateButtons(BOOL btn1, BOOL btn2, BOOL btn3){
button1.enabled = btn1
button2.enabled = btn2
button3.enabled = btn3
}
It's possible to create an Objective-C method with a variable argument list, as Matt Gallagher explains in Variable argument lists in Cocoa. Variable argument lists are even used in the Foundation framework, e.g. +[NSArray arrayWithObjects:...].
That said, it's probably a lot less work to pass the list of buttons in your method as an array, particularly given the ease with which one can now create arrays using object literals:
[foo updateFields:#[button1, button2, button3]];
I have seen so many helpful threads here, but this is my first time posting!
I was working on the infamous Stanford OpenCourse project: Matchismo. While I got everything going just fine, but I don't understand one part of the sample codes.
Basically the code below is used to get a Card object to compare with another card.
- (void) flipCardAtIndex: (NSUInteger)index
{
Card *card = [self cardAtIndex:index];
if (card && !card.isUnplayable)
{
if (!card.isFaceUp)
{
for (Card* otherCard in self.cards)//for-in loop
{
if (otherCard.isFaceUp && !otherCard.isUnplayable)
{
int matchScore = [card match:#[otherCard]];
......
And this is how cardAtIndex works:
-(Card *) cardAtIndex:(NSUInteger)index
{
if (index < [self.cards count])
//dot notation is used for property
//[] is used for method
{
return self.cards[index];
}
return nil;
}
Here are the methods for Match(card*) and Match(playingCard)
Match(card*)
-(int) match:(NSArray *)otherCards
{
NSLog(#"here");
int score = 0;
for (Card *card in otherCards)
{
if ([card.content isEqualToString:self.content])
score = 1;
{
NSLog(#"Card Match");
}
}
return score;
}
Match(PlayingCard*)
-(int) match: (NSArray *)otherCards;
{
int score = 0;
if ([otherCards count] == 1)
{
PlayingCard *otherCard = [otherCards lastObject];//the last object in the array
if ([otherCard.suit isEqualToString:self.suit])
score = 1;
else if (otherCard.rank == self.rank)
score = 4;
NSLog(#"PlayingCard Match");
}
return score;
}
It worked just fine, but I don't get why when a Card* object calls a method, its subclass's PlayingCard's method is invoked.
Thanks so much for help me!
This concept is called Polymorphism.
It allows you to have a base class which provides some interface, and a set of subclasses that implement these methods in some different ways. The classic example is a Drawable class method draw, and its subclasses Circle and Rectangle, that both override the draw method to render themselves in some specific manner.
So goes for your Card base class, it calls its own interface method match, but as an object is actually not an instance of Card, but of a PlayingCard subclass, subclass method gets called instead to provide specific implementation.
In your view controller .m file, the property "deck" must be initialized as class PlayingCardDeck, and in PlayingCardDeck.m, the class of card is PalyingCard. So even though you declared your card as class Card, the method it calls will still be the one in class PlayingCard.
Is it possible to implement something like a Smalltalk-style whileTrue: method in Objective-C using blocks? Specifically, instead of:
int count = 0;
while (count < 10)
{
NSLog(count);
count++;
}
I'd like to be able to do (via a wrapper on the bool primitive called OOBoolean) something like...
__block int count = 0;
[[OOBoolean booleanWithBool: count < 10] whileTrueDo: ^() {
NSLog(count);
count++;
}];
I'm having trouble understanding how this would be implemented though...
Here you have a couple of ideas,
Assuming your bool wrapper implements boolValue, a naive implementation could be:
-(void) whileTrueDo:(void (^)(void)) block{
while ([self boolValue]) {
block();
}
}
In order for the wrapper to change its bool value after each iteration, the block must be able to actually change the variable that is used to calculate the boolean condition. So, in your case, by setting the __block type modifier to count, and increasing count in each block execution, you should be able to make it work.
The problem is, if you create your wrapper by sending the evaluated condition, as you stated in your question, you wont be able to change its bool value in each iteration. So, I would change the way the wrapper is created and the whileTrueDo: naive implementation so the boolean wrapper uses an evaluation block.
__block int count = 0;
OOBooleanBlock evaluationBlock = ^BOOL{
return count < 10;
};
[[OOBoolean booleanWithBlock:evaluationBlock] whileTrueDo: ^() {
NSLog(count);
count++;
}];
//In OOBoolean
+(OOBoolean*) booleanWithBlock:(OOBooleanBlock) evaluationBlock{
//Instantiate, set the evaluationBlock ivar and return the ooboolean object.
}
-(void) whileTrueDo:(void (^)(void)) block{
while (self.evaluationBlock()) {
block();
}
}
Remember to use the __block type modifier, otherwise you will enter in an infinite loop.
I haven't tested this, I hope this helps you though.
Cheers
I created a new function to log every method from a class in runtime.
The problem that I have is in this line :
id value = va_arg(stackFrame, id);
Doesn't convert the type of object inside the arguments.
Any idea on what I'm doing wrong? Is there another way to do this?
void DebugArguments ( id self, SEL _cmd,...)
{
id receiver = self;
SEL receiverSelector = _cmd;
va_list stackFrame;
va_start(stackFrame, _cmd);
NSMethodSignature *signature
= [receiver methodSignatureForSelector:receiverSelector];
NSUInteger count = [signature numberOfArguments];
NSUInteger index = 2;
for (; index < count; index++)
{
id value = va_arg(stackFrame, id);
if (!value)
{
NSLog(#"Arguments: %#",value);
}
}
va_end(stackFrame);
}
I call the function InitDebug from a class like this : -
(void)MyTest:(NSString *)string {
InitDebug(self, _cmd); } I hope
to log the Argument string from the
method MyTest.
In the future, it is helpful to show all the code.
In any case, you can't do that; when you call InitDebug(...), you are pushing a new frame onto the stack and va_arg() will decode in the context of that frame, not the surrounding frame. Nor can you "go up the stack" and start grubbing about in the arguments of the calling frame as there is no guarantee that the calling frame is even preserved at that point.
If you really want to do something like this, you would probably want to subclass NSProxy and use it is a proxy between the caller and whatever object you want to log. You could then leverage the built-in forwarding mechanism of Objective-C to muck about with the arguments.
The common Superclass of Rectangle and Circle is Shape.
If I initialize some shapes, what is a good way of converting the shape into a circle later and keeping the same properties set while it was a shape? Should I implement a initWithShape in the subclasses that looks something like this?
- (id) initWithShape:(Shape*)aShape {
self = (id) aShape;
// set circle or rectangle specific values
return self;
}
Does anyone have an example that I can look at?
Don't do what you just did. Think about what happens when you do this:
Shape *shape = ...;
Rectangle *rect = [[Rectangle alloc] initWithShape:shape];
In the second line, an instance of Rectangle gets allocated. Then, the return value for initWithShape is just shape again, so the new Rectangle that we just allocated has been leaked!
The cast to id is also unnecessary—any Objective-C object can be implicitly cast to id.
I'm not entirely clear on what you're trying to do. Perhaps if you clarified your question, I could tell you what you should be doing.
You cannot change an object after it has been created, except by freeing it and creating a new one (which you can do in an init method, and is in fact quite often done for singletons or class clusters), but that is not really what you're after.
Give an existing Shape object, with some properties, your only real option is to create a new object based on the shape properties. Something like:
In Shape.m:
- (id) initWithShape:(Shape*)aShape {
self = [super init];
if (self != nil) {
// copy general properties
_x = aShape.x;
_y = aShape.y;
_color = [aShape.color copy];
}
return self;
}
In Circle.m:
- (id) initWithShape:(Shape*)aShape {
self = [super initWithShale:aShape];
if (self != nil) {
// base properties on the class of the shape
if ( [aShape isKindOfClass:[Oval class]] ) {
// average the short and long diameter to a radius
_radius = ([(Oval*)aShape shortDiameter] + [(Oval*)aShape longDiameter])/4;
} else {
// or use generic Shape methods
_radius = aShape.size / 2;
}
}
return self;
}
If you have a reference to a Shape, and it might be a Rectangle or Pentagram or whatever, and you want to 'convert' to a circle (I guess you mean a circle with the same bounding box?), you have to create a new object. You can't change the class of an object after it's been created (except through very nasty low-level hacks.)
So yes, you would create an -initWithShape: method in class Circle. But the method would look like a normal init method, setting up the instance variables of the new Circle object ('self'). It would access properties of the given Shape, like its position and size, and set up the new object accordingly.
Why not implement a method in your shapes to take properties from other shapes rather than trying to replace the instance of the object altogether. It's probably safer.
// for rectangle
- (void) takePropertiesFrom:(Shape *) aShape
{
if ([aShape isKindOfClass:[Circle class]])
{
float radius = [aShape radius];
[self setWidth:radius * 2];
[self setHeight:radius * 2];
}
else
{
[self setWidth:[aShape width]];
[self setHeight:[aShape height]];
}
}
// for circle
- (void) takePropertiesFrom:(Shape *) aShape
{
if ([aShape isKindOfClass:[Rectangle class]])
[self setRadius:[aShape width] / 2];
else
[self setRadius:[aShape radius]];
}
Obviously you would want to set up a public interface for Shape that exposes the basic properties of a shape, such as height and width, and then you won't need to hard-code property stealing based on class type.