0

I'm writing an iOS game that has configurable waves of enemies. I have one generic wave class that can be configured with the enemies, etc.

When a wave is started, I'd like to have a callback method for running custom code every level. I've been reading that objective-c doesn't have a way to define inline classes or anonymous functions, but I'd really like to avoid creating a separate header/class for every callback I need to use - mainly because the callbacks will only be a few lines.

In java, I'd do this:

wave.addCallback( new WaveCallback(){
  public void onStart(){
    // do some stuff
  }
});

In iOS, I have this:

Wave *wave1 = [[Wave alloc] init];
[wave1 addEnemy:@"BasicSpaceship"];
// need to tell the wave to execute a few lines of code when started
[waves addObject:wave1];
Bhaumik Surani
  • 1,730
  • 3
  • 19
  • 40
helion3
  • 34,737
  • 15
  • 57
  • 100
  • 1
    wouldn't you be able to utilize a code block for this? Judging by what you'd do in java I think a code block would suite your needs just fine. – Antwan van Houdt Jul 05 '14 at 15:44
  • Perhaps you'd like to look into blocks. – duci9y Jul 05 '14 at 15:45
  • obj-c is still new to me, sounds like I need to look into code blocks. – helion3 Jul 05 '14 at 15:45
  • Do you wish to run code on the object configuring `Wave` or run code independent of the object doing that? – duci9y Jul 05 '14 at 15:46
  • I want to pass the code to `wave1` so that when the wave is actually started, it can execute the code block – helion3 Jul 05 '14 at 15:53
  • Really? You read that there's [no anonymous functions in ObjC](http://www.google.com/search?q=objective-c+anonymous+functions)? – jscs Jul 05 '14 at 18:49

4 Answers4

1

In Objective-C you would use one of many patterns. Either create a method that has a block argument, so you can add code to the block, or use the delegate pattern, where you create a delegate protocol, and set a delegate that implements a method that is called.

Both are used in Cocoa for callbacks. You'll do well to look at examples of both and decide what works best for you.

If it's a one off call with a few parameters a block would work. If you need to handle a large set of parameters or events, you might want to go the delegate route.

You can also use NSNotification. Notifications can be posted when something happens. Any object can register as an observer and respond to the notification. Notifications can carry a payload of info or not.

You can use key value observing KVO. This is similar to notifications but focuses on property changes.

uchuugaka
  • 12,679
  • 6
  • 37
  • 55
0

Unless I'm misunderstanding the problem, I would structure your objects differently. I would create a base Wave class that simply does what you've declared. The base class has a protocol for OnStart so that all children need to define that implementation:

@interface Wave1 : Wave

- (void) OnStart;

And then it's basically how you defined it above:

Wave *wave = [[Wave1 alloc] init];
[wave addEnemy:@"BasicSpaceship"];
[wave OnStart];
[waves addObject:wave];
Oren
  • 5,055
  • 3
  • 34
  • 52
  • But I don't want a child class for every single wave, that's what I'm trying to avoid. Just an easy way to define a few lines of code to be executed when the wave starts. – helion3 Jul 05 '14 at 17:18
0
- (void) StartWave: (void(^)(void)) onStarted
{
    Wave *wave = [[Wave alloc] init];
    [wave addEnemy:@"BasicSpaceship"];
    [waves addObject:wave];

    onStarted();
}

Then you can call this method like this:

[self StartWave:^(void){
    NSlog(@"I just started wave 1");
}];

[self StartWave:^(void){
    NSlog(@"I just started wave 2");
}];
Oren
  • 5,055
  • 3
  • 34
  • 52
-1

Comments pointed me towards code blocks, which I can pass to a property on the wave class:

How to store blocks in properties in Objective-C?

Community
  • 1
  • 1
helion3
  • 34,737
  • 15
  • 57
  • 100
  • Alternatively you can use delegation and action targets. – Amin Negm-Awad Jul 05 '14 at 16:12
  • Blocks don't have to be stored as properties. They can simple be written inline also. – uchuugaka Jul 05 '14 at 16:30
  • But inline won't help me because it needs to be executed at a later time – helion3 Jul 05 '14 at 16:53
  • why not add it to an array? – vikingosegundo Jul 05 '14 at 16:58
  • An inline block *will* be executed at a later time. When you pass the block to the function (similar to anonymous classes in Java), it's the responsibility of the called method to execute your block when desired. It is possible for an inline block passed to a method to never even be executed. – Craig Otis Jul 05 '14 at 18:05
  • It would still have to store the block passed as an argument to execute it at a later time - doesn't *have* to be in an @property, but some class-level variable, correct? – helion3 Jul 05 '14 at 19:03