Re: Lost memory, GCD, dispatch sources, Cocoa bindings & User interface
Re: Lost memory, GCD, dispatch sources, Cocoa bindings & User interface
- Subject: Re: Lost memory, GCD, dispatch sources, Cocoa bindings & User interface
- From: Charles Srstka <email@hidden>
- Date: Wed, 16 Sep 2015 14:49:41 -0500
> On Sep 16, 2015, at 1:45 PM, Ken Thomases <email@hidden> wrote:
>
> This is not legitimate. The -willChangeValueForKey: must occur before the property, as seen via its getter, has changed. This is necessary for observers who ask for the old value, which can include KVO itself for key paths which go through the property.
>
> By dispatching it asynchronously, you allow the setting of privateFoo to potentially happen before the -willChangeValueForKey: call.
>
> Also, if multiple background threads set the foo property simultaneously, their willChange… and didChange… calls can interleave, which is not kosher. So, using dispatch_sync() wouldn't even solve the problem.
>
> You would have to surround the whole body of the setter with a single dispatch call (sync or async). And the getter would have to also dispatch synchronously to the main queue so that it's properly coordinated and consistent with calls to the setter. At that point, it's just better to move the setting of the property like Jean did.
Hmm, good point; I hadn’t really thought of observers that ask for the old value. Pushing reads and writes to the main queue is doable, though; you just have to put checks in that you’re not already on the main thread, in order to avoid deadlocks (and to avoid weirdness caused by code on the main thread calling the setter, and then the value not being set if the same code subsequently calls the getter again in the same iteration of the run loop. If you’re not calling the setter from the main thread, you can remove that check).
@implementation MyClass {
MyObject *_foo;
}
- (instancetype)init {
self = [super init];
if (self == nil) {
return nil;
}
return self;
}
+ (BOOL)automaticallyNotifiesObserversOfFoo {
return NO;
}
- (MyObject *)foo {
__block MyObject *foo;
if ([NSThread isMainThread]) {
foo = _foo;
} else {
dispatch_sync(dispatch_get_main_queue(), ^{
foo = _foo;
});
}
return foo;
}
- (void)setFoo:(MyObject *)foo {
void (^setter)() = ^{
[self willChangeValueForKey:@"foo"];
_foo = foo;
[self didChangeValueForKey:@"foo"];
};
if ([NSThread isMainThread]) {
setter();
} else {
dispatch_async(dispatch_get_main_queue(), ^{
setter();
});
}
}
@end
Charles
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please 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
References: | |
| >Lost memory, GCD, dispatch sources, Cocoa bindings & User interface (From: Jean Suisse <email@hidden>) |
| >Re: Lost memory, GCD, dispatch sources, Cocoa bindings & User interface (From: Quincey Morris <email@hidden>) |
| >Re: Lost memory, GCD, dispatch sources, Cocoa bindings & User interface (From: Charles Srstka <email@hidden>) |
| >Re: Lost memory, GCD, dispatch sources, Cocoa bindings & User interface (From: Ken Thomases <email@hidden>) |
- Prev by Date:
Re: Lost memory, GCD, dispatch sources, Cocoa bindings & User interface
- Next by Date:
Re: Lost memory, GCD, dispatch sources, Cocoa bindings & User interface
- Previous by thread:
Re: Lost memory, GCD, dispatch sources, Cocoa bindings & User interface
- Next by thread:
Re: Lost memory, GCD, dispatch sources, Cocoa bindings & User interface
- Index(es):