This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revision | |||
manual:enhanced_events [2013/05/28 15:52] – [Block-based Event Listeners] daniel | manual:enhanced_events [2014/02/05 09:54] (current) – [Conclusion] daniel | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ====== Enhanced Events ====== | ||
+ | |||
+ | ===== Simplified Event Dispatching ===== | ||
+ | |||
+ | To dispatch an event, you create an event object and pass it to the " | ||
+ | |||
+ | <code objc> | ||
+ | SPEvent *event = [SPEvent eventWithType: | ||
+ | [self dispatchEvent: | ||
+ | </ | ||
+ | |||
+ | What I didn't show you before is that there is an alternative method that does just the same, but is more concise: you can let Sparrow create the event for you and dispatch it right away. | ||
+ | |||
+ | <code objc> | ||
+ | [self dispatchEventWithType: | ||
+ | |||
+ | // or | ||
+ | [self dispatchEventWithType: | ||
+ | </ | ||
+ | |||
+ | That has exactly the same effect as the previous sample. Note, however, that this only works with standard events; if you need to dispatch a custom event subclass, you have to use the traditional method. | ||
+ | |||
+ | ===== Block-based Event Listeners ===== | ||
+ | |||
+ | A rather new feature of Objective-C are " | ||
+ | |||
+ | That's why Sparrow 2.0 introduced block-based event listeners. In the previous section, you saw event handlers declared at class level: a method would be called on a certain object when an event was dispatched. | ||
+ | |||
+ | The concise alternative to this approach is to define the event listener as a block, like this: | ||
+ | |||
+ | <code objc> | ||
+ | [button addEventListenerWithType: | ||
+ | { | ||
+ | | ||
+ | }]; | ||
+ | </ | ||
+ | |||
+ | The thing starting with the caret (^) is the block. In essence, it's really nothing else than a function with one parameter of type " | ||
+ | |||
+ | Block event handlers have several advantages: | ||
+ | |||
+ | * You can add your event handler directly inline, | ||
+ | * which is less code to type and | ||
+ | * allows you to directly access any variables of the outer scope. | ||
+ | |||
+ | Let's look at a more complete example. We want to create a button that toggles the visibility of an image object. | ||
+ | |||
+ | <code objc> | ||
+ | - (id)init | ||
+ | { | ||
+ | if ((self = [super init])) | ||
+ | { | ||
+ | SPImage *image = [SPImage imageWithTexture: | ||
+ | SPButton *button = [SPButton buttonWithUpState: | ||
+ | | ||
+ | [button addEventListenerWithType: | ||
+ | { | ||
+ | image.visible = !image.visible; | ||
+ | }]; | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Note that we didn't have to create a new instance method; the block is defined directly inline. But what's even more interesting is that we could access the " | ||
+ | |||
+ | If we used the conventional, | ||
+ | |||
+ | ==== Beware of Retain Cycles! ==== | ||
+ | |||
+ | If you use this type of event handler, there is one thing you have to be careful about, though. Per default, a block will " | ||
+ | |||
+ | Let's look at an example. | ||
+ | |||
+ | <code objc> | ||
+ | @implementation Game | ||
+ | |||
+ | - (id)init | ||
+ | { | ||
+ | if ((self = [super init])) | ||
+ | { | ||
+ | [self addEventListenerForType: | ||
+ | { | ||
+ | [self startAnimations]; | ||
+ | }]; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | - (void)startAnimations | ||
+ | { | ||
+ | // ... | ||
+ | } | ||
+ | |||
+ | @end | ||
+ | </ | ||
+ | |||
+ | When you compile this, Xcode will display the following warning: | ||
+ | |||
+ | Capturing ' | ||
+ | |||
+ | <note warning> | ||
+ | Do not ignore this warning! If you do, you will certainly leak some memory. | ||
+ | </ | ||
+ | |||
+ | The reason for this is that the block retains " | ||
+ | |||
+ | Thankfully, that situation is easy to solve. You can create a new variable that references " | ||
+ | |||
+ | <code objc> | ||
+ | __weak Game *weakSelf = self; | ||
+ | |||
+ | [self addEventListenerForType: | ||
+ | { | ||
+ | [weakSelf startAnimations]; | ||
+ | }]; | ||
+ | </ | ||
+ | |||
+ | This will not only happen when you access " | ||
+ | |||
+ | ==== Changing Variables in the Block ==== | ||
+ | |||
+ | In the following sample, we want to count the number of times someone has pressed a button. This is our first attempt at doing so: | ||
+ | |||
+ | <code objc> | ||
+ | int hitCount; | ||
+ | | ||
+ | [button addEventListenerForType: | ||
+ | { | ||
+ | | ||
+ | | ||
+ | }]; | ||
+ | </ | ||
+ | |||
+ | Unfortunately, | ||
+ | |||
+ | Variable is not assignable (missing __block type specifier) | ||
+ | |||
+ | This time, Xcode was even nice enough to tell us about the solution! Just add a block qualifier to the variable. | ||
+ | |||
+ | <code objc> | ||
+ | __block int hitCount; | ||
+ | </ | ||
+ | |||
+ | That will fix the error. | ||
+ | |||
+ | ==== Conclusion ==== | ||
+ | |||
+ | As you can see, blocks are not 100% fail-safe. Still: if you listen to Xcode' | ||
+ | |||
+ | |||
+ | |||
+ | ------- | ||
+ | |||
+ | //Next Section: [[Touch Events]] | ||