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
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?
KVO isn’t really the right hammer for your nail, but I’m not sure I understand your scenario properly. You have a Brain which every «interval» picks a task to work on and does some work. KVO is about observing changes in a key’s value and doing something with it. It’s an inter-object dependency mechanism. A common way to use it is to update some UI when the value of a model object’s key changes. An example: You have a table view which shows the current state of all your tasks. Each task is just a countdown from 10 to 0, and you want the table to display what stage in the countdown each object is at. Your controller observes all the tasks, and when a task changes it tells the appropriate row in the table to refresh. In your case, the Brain has nothing the tasks are interested in observing. “I’m doing some work” doesn’t make sense from an OO point of view since the Brain should be doing the work and not the Task. Hope that helps, -Ben
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@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@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
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@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@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@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
_______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
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@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@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@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@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
_______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
_______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
participants (3)
-
Benjamin Stiglitz
-
Brian Chapados
-
Matt Aimonetti