I have an ObjC class RuleSet
that needs quite heavy initialization (parses a big JSON file, does lots of querying into several OS services, applies heuristics, and last, it builds a set of complicated NSPredicates
, that can later be used for fast evaluation.
My program (except for this object) receives high-priority events from MacOS (EndpointSecurity framework) and has to respond to these within very narrow deadlines - based on the fast evaluation of my current RuleSet
instance.
I handle those events in a special (highest priority) concurrent dispatch_queue
I created.
However... if I receive some external trigger, to change my RuleSet
- and I need to build the new RuleSet
instance before applying it, I want the code creating it not to know about the internal structure of dispatch queues, and simply call
RuleSet *newRules = [[RuleSet alloc] initWithJSON:newJSONPath];
[myEventHandlingEngine setRuleSet:newRuleSet];
I'd like the RuleSet init to be able to somehow defer the work to another, low-priority serial dispatch_queue, maybe in parts. I don't mind blocking the caller until I'm done (this heavy init shouldn't take more than a second...). still, it's important that I do it on a queue that has lower priority - so that incoming events will be handled first.
Now I tried to write things like
- (instancetype) initWithJSON:newJSONPath:(NSString *)jsonFilePath
{
dispatch_sync([RuleSet setupQueue], ^{
if ( nil == (self = [super init]) ) {
self = nil;
return self;
}
// heavy work here
});
return self;
}
but that of course won't even compile because 'self' isn't a __block variable, and I'm not sure it can be...
Any advice on how to go about this?
You should try using a dispatchGroup to handle that situation :
- (instancetype) initWithJSON:newJSONPath:(NSString *)jsonFilePath
{
if ( nil == (self = [super init]) ) {
self = nil; //This seems useless since self is already nil ?
return self;
}
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, [OITPreventionPolicy policySetupQueue], ^{
// Execute your heavy work here
});
// Wait for the group to finish its work (you could replace 'forever' by a timeout)
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
return self;
}
The call to dispatch_group_wait
will block the thread in which the object is created (so it cannot be the main thread).