[MacRuby-devel] kvo vs referenced hash
Brian Chapados
chapbr at gmail.com
Tue Sep 8 20:59:26 PDT 2009
Yes, it could work that way too. In this scenario where you just need
to call #update, if the game controller keeps an array/set of child
items, you could just call
[gameItems makeObjectsPerformSelector:@selector(update)];
You would use KVO in the following hypothetical scenario, which is
adopted from one of the chapters in Hillegass. It's a great pattern
showing how to use KVO to support change management + undo support.
Imagine your game items are "bugs" crawling around the screen. The
player can click/tap on them, which makes them change color. They can
also change color in other game scenarios, which may not require
direct interaction by the player. You'd have a "Bug" model class,
with a color property.
Assuming you have an array-like property named 'bugs'...
---
note:
You could get that by actually having an NSArray *bugs, or by
implementing the methods below, which could manipulate some other
state...
- (NSArray *) bugs;
- (NSUInteger) countOfBugs;
- (Bug *) objectInBugsAtIndex:(NSUInteger)index;
----
When the game controller adds a bug, your insert method will get called...
- (void) insertObject:(Bug *)aBug inBugsAtIndex:(NSUInteger)index
{
// start observing the color property...
[self startObservingBug:aBug];
}
- (void) startObservingBug:(Bug *)aBug
{
[aBug addObserver:self forKeyPath:@"color"
options:NSKeyValueObservingOptionOld context:nil];
}
In the game controller, you can respond respond to bugs changing color
for any reason by implementing:
- observeValueForKeyPath:ofObject:change:context:
in this method:
- record an "undo" action so that the user can take back the action
that caused the change, using a setter than can handle inverse
actions, something like:
- (void) changeKeyPath:(NSString *)keyPath ofObject:(id)object toValue:(id)value
{
[object setValue:value forKeyPath:keyPath];
}
when the bug dies or gets removed from the array, you handle it here:
- (void) removeObjectFromBugsAtIndex:(NSUInteger)index
{
// stop observing:
[self stopObservingBug:[bugs objectAtIndex:index]];
}
- (void) stopObservingBug:(Bug *)aBug
{
[aBug removeObserver:self forKeyPath:@"color"];
}
This example uses both KVC & KVO. Powerful stuff.
Brian
On Tue, Sep 8, 2009 at 1:54 PM, Matt Aimonetti<mattaimonetti at gmail.com> wrote:
> The project is a simple demo game using the same approach explained by Brian
> where game items listen for notifications and update themselves based on the
> notification.
> For some reasons, I think it would be easier for the game controller to know
> about the game items and call #update on each of them directly.
>
> - Matt
>
>
>
> On Tue, Sep 8, 2009 at 1:18 PM, Brian Chapados <chapbr at gmail.com> wrote:
>>
>> I am also not sure that I fully understand this scenario, but it
>> doesn't appear that you would need KVO. Do the "tasks" or the "Brain"
>> have any properties to observe?
>>
>> As Ben points out, KVO really shines when you need to keep a UI in
>> sync with the state of a model.
>>
>> If "tasks" just need to know when the "Brain" is done thinking, I
>> would just use standard notifications.
>>
>> NSString * const BrainFinishedThinkingNotification =
>> @"BrainFinishedThinkingNotification"
>>
>> When the Brain has a thought... send a notification:
>>
>> (inside Brain class)
>>
>> - (void) thinkOfSomething
>> {
>> // create idea
>>
>> // send notification when finished
>> [[NSNotificationCenter defaultCenter]
>> postNotificationName:BrainFinishedThinkingNotification
>> withObject:self];
>> // (you could include extra data in a userInfo object)
>> }
>>
>> That's it, the Brain doesn't have to know about Tasks.
>>
>> The task class can then register for changes, and respond to the
>> notification:
>>
>> [[NSNotification defaultCenter] addObserver:self
>> selector:@selector(brainFinishedThinking:)
>> name:BrainFinishedThinkingNotification object:nil];
>>
>> handle them in:
>> - (void) brainFinishedThinking:(NSNotification *)n
>> {
>> // access the Brain if necessary
>> Brain *theBrain = (Brain *)[n object];
>>
>> // do something
>> }
>>
>> Tasks don't need an explicit reference to Brain.
>>
>> Brian
>>
>> On Sat, Sep 5, 2009 at 2:16 AM, Matt Aimonetti<mattaimonetti at gmail.com>
>> wrote:
>> > Hi list,
>> >
>> > Coming from a Ruby background, I try to understand and pick the best
>> > from
>> > Obj-C/Cococa and learn how to use brilliant ideas to improve my coding.
>> >
>> > Tonight I was working on a simple demo app to learn how things are done
>> > in
>> > the Obj-C world and see how they would transpose to the MacRuby world.
>> >
>> > Everything went well until the KVO question came along.
>> >
>> > Let's say I have a controller that we are going to call Brain.
>> > We also have a lot of simpler objects that don't do anything but having
>> > a
>> > state and being displayed, we are going to call them Task instances. The
>> > brain is called every X seconds to "think".
>> >
>> > My understanding is that an Obj-C developer would register all the tasks
>> > instance with the brain using a KVO and the brain would send
>> > notifications
>> > when it's being called to "think". So, every time a new task is being
>> > created, an observer is added on the brain with the new task key. Each
>> > Task
>> > instance has an observeValueForKeyPath:ofObject:change:context: method
>> > implemented which checks that the notification is meant for itself and
>> > if it
>> > is, to act accordingly.
>> >
>> > While the concept is simple and attractive. I wonder if it wouldn't be
>> > simpler to forget about kvo's and simply keep the list of registered
>> > tasks
>> > in the brain and the brain would call the tasks directly and tell them
>> > to
>> > change.
>> >
>> > It sounds to me that in the MacRuby world, it would be more efficient.
>> > If we
>> > have 250 tasks for instance, when a notification is being sent, every
>> > single
>> > task in the 250 tasks created, will receive the notification and will
>> > check
>> > what to do with it. If we had a simple hash/dictionary in the brain, we
>> > could directly find the task to handle and call it directly without
>> > having
>> > to go through the 250.
>> >
>> > Am I missing something or in this specific case and because we use Ruby,
>> > KVO
>> > aren't the way to go?
>> >
>> > Thanks for your help,
>> >
>> > - Matt
>> >
>> > _______________________________________________
>> > MacRuby-devel mailing list
>> > MacRuby-devel at lists.macosforge.org
>> > http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
>> >
>> >
>> _______________________________________________
>> MacRuby-devel mailing list
>> MacRuby-devel at lists.macosforge.org
>> http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
>
>
> _______________________________________________
> MacRuby-devel mailing list
> MacRuby-devel at lists.macosforge.org
> http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
>
>
More information about the MacRuby-devel
mailing list