Re: KVO using threads
Re: KVO using threads
- Subject: Re: KVO using threads
- From: "Paulo F. Andrade" <email@hidden>
- Date: Thu, 10 May 2007 09:42:14 +0100
You're absolutely right!
I just put the pointer inside an NSValue a passed that.
Thanks for noticing that mistake.
Paulo F. Andrade 52439@IST
mailto: email@hidden
On 2007/05/09, at 21:04, Chris Kane wrote:
Note that context is not necessarily either nil or an object, so
giving it to "arrayWithObjects:..." is not good at all.
Chris Kane
Cocoa Frameworks, Apple
On May 9, 2007, at 11:39 AM, Paulo F. Andrade wrote:
Ok I have tested this now and can confirm that it works as expected.
I had to make a slight change to the code earlier, here is the
working version for future reference :)
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)
object change:(NSDictionary *)change context:(void *)context
{
NSArray *args = [NSArray arrayWithObjects: keyPath, object,
change, context, nil];
//call the helper method
[self performSelectorOnMainThread:@selector(auxiliaryMethod:)
withObject:args waitUntilDone:NO modes:[NSArray
arrayWithObject:NSDefaultRunLoopMode]];
}
- (void)auxiliaryMethod:(NSArray *)args
{
NSString *keyPath;
id object;
NSDictionary *change;
void *context;
@try {
keyPath = [args objectAtIndex:0];
object = [args objectAtIndex:1];
change = [args objectAtIndex:2];
context = [args objectAtIndex:3];
}
@catch (NSException * e) {
// usually occurs because when constructing the NSArray args,
context is nil
// meaning that the array only has 3 positions instead of 4
}
@finally {
[super observeValueForKeyPath:keyPath
ofObject:object
change:change
context:context];
}
}
Paulo F. Andrade 52439@IST
mailto: email@hidden
On 2007/05/09, at 11:57, Paulo F. Andrade wrote:
Hi,
First of all, thank you very much for your help.
I think I have understood your Receptionist pattern. However
because, as you said, it is difficult to interpose the proxy-like
object in all situations, I was thinking of doing it slightly
different.
I would subclass my controller (in my case an NSArrayController)
and override the observeValueForKeyPath:... to call the super
version of the method, using the perfomSelectorOnMainThread: .
Because I can only send one argument using
performSelectorOnMainThread: I would need a helper method to do
this.
Maybe it's better to write some code, here goes:
@implementatiton ArrayControllerSubclass
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)
object change:(NSDictionary *)change context:(void *)context
{
NSArray *args = [NSArray arrayWithObjects: keyPath, object,
change, context, nil];
//call the helper method
[self performSelectorOnMainThread:@selector(auxiliaryMethod:)
withObject:args waitUntilDone:NO modes:[NSArray
arrayWithObject:NSDefaultRunLoopMode]];
}
- (void)auxiliaryMethod:(NSArray *)args
{
[super observeValueForKeyPath:[args objectAtIndex:0] ofObject:
[args objectAtIndex:1] change:[args objectAtIndex:2] context:
[args objectAtIndex:3]];
}
@end
Before going about testing this, does anybody see something
terribly wrong with this approach that I'm overlooking?
As for the sending KVO side, I'm already using Core Data with my
domain objects. So putting a synchronized(self){...} on the
mutator methods would suffice to keep willChange and didChange
ordered.
Thank you for your time!
Paulo F. Andrade 52439@IST
mailto: email@hidden
On 2007/05/01, at 22:11, Chris Kane wrote:
Actually KVO and its messages are thread-safe. But the objects
that send (by having their properties changed, say) and receive
(observers) the KVO notifications may not be thread-safe, or
expect to receive the messages on different threads, which may
require special additional actions to handle. Such is the case
with the Bindings-related objects (like the controllers) in AppKit.
One general solution might be to interpose a proxy-like object
between the model objects (presumably thread-safe) and the
controllers. I called this a receptionist pattern in my WWDC
2006 talk. The receptionist object should implement
observeValueForKeyPath:..., you should initialize the
receptionist with the real object (say, a controller), and you
should use the receptionist wherever you would otherwise refer
to the controller. (This last step is sometimes difficult to do
in all cases.) When the receptionist receives a KVO
observeValue... call, it should save the parameters in a little
private helper object, and send itself a private message to be
performed on the main thread (performSelectorOnMainThread...) to
deliver that message with its parameters to the real object
(which will be on the main thread then). No, I don't have an
example which does this.
That handles (if you can pull it off) the model -> controller ->
view data flow direction. Presumably if your model objects are
thread-safe, changes on the main thread coming down from the
view to the model objects will be fine.
On the sending (KVO-notification-causing) side of things, using
automatic KVO is not entirely thread-safe because the willChange/
change/didChange combination is not atomic. Using manual KVO
(sending the willChange... and didChange... methods yourself in
all the right places) you can make these atomic with your own
lock (I suggest using the object itself as the lock with
@synchronized() is a reasonable default choice of locking
technique). Using automatic KVO can, for example, make the
change dictionary that observers get completely wrong with
respect to the change that occurred due to execution ordering
issues.
Chris Kane
Cocoa Frameworks, Apple
On May 1, 2007, at 12:24 PM, Scott Anguish wrote:
No. KVO messages are not threadsafe.
On May 1, 2007, at 2:40 PM, Paulo F. Andrade wrote:
Hi!
Does KVO work when the changes are made in different thread?
I'm changing a tooMany relationship using the add<Key>Object:
method generated by the Xcode modeling tool.
The changes however aren't reflected in my tableview. I've
also tried using the mutableSetForKey:.
I know my tableView is set up correctly because if I restart
my application (causing all changes do flush to the SQLite
store), every change I made shows up correctly!
I've search the net for this and found that Bindings don't
work with DO, does this means they don't work with threads?
Paulo F. Andrade 52439@IST
mailto: email@hidden
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
40mega.ist.utl.pt
This email sent to email@hidden
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden