How to prevent dispatch group to not crash? - objective-c

I am using the below code to wait for async tasks to be completed. It works a couple of times and crashes. The updateFromTable always invokes callback() so that the group calls are balanced, but it still crashes.
- (void)updateFromTable:(Table *)table env:(Env *)env callback:(void (^)(void))callback {
[someasync usingBlock:^{
callback()
}];
}
- (NSString * _Nullable)process {
JSL * __weak weakSelf = self;
NSString __block *ret = nil;
dispatch_group_enter(_dispatchGroup);
dispatch_async(_repQueue, ^{
JSL *this = weakSelf;
[this updateFromTable:[this->_env table] env:this->_env callback:^{
ret = [some op .. ];
dispatch_group_leave(this->_dispatchGroup);
}];
});
dispatch_group_wait(_dispatchGroup, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC));
info(#"%#", #"done");
return ret;
}
Any idea why it crashes randomly and how to fix this? Basically, what I am trying to achieve is invoke couple of async tasks, wait for all of them to complete and then proceed with the rest.
Referring: How to wait past dispatch_async before proceeding?

You cannot dereference ivars with -> if this is nil. So, the typical solution is to create strong reference that can’t be deallocated while the closure runs, and return if it’s nil:
- (NSString * _Nullable)process {
typeof(self) __weak weakSelf = self;
[self asynchronousMethodWithCompletion:^{
typeof(self) strongSelf = weakSelf;
if (!strongSelf) { return; }
// can now safely use `strongSelf` here
});
...
}
This is “weakSelf-strongSelf dance”. You use it in situations where you need to make sure that self isn’t nil when you use it, e.g. dereferencing ivars (strongSelf->ivar) .
Thus:
- (NSString * _Nullable)process {
typeof(self) __weak weakSelf = self;
NSString __block *ret = nil;
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);
dispatch_async(_repQueue, ^{
typeof(self) strongSelf = weakSelf;
if (!strongSelf) { return; }
[strongSelf updateFromTable:[strongSelf->_env table] env:strongSelf->_env callback:^{
ret = [some op .. ];
dispatch_group_leave(group);
}];
});
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
info(#"%#", #"done");
return ret;
}
A few other observations:
The dispatch group should be a local variable of the method rather than an ivar. There’s no need for anything else in your code referencing this group.
Make sure that your dispatch_group_leave calls don’t exceed the number of dispatch_group_enter calls (i.e. that this completion handler block isn’t called multiple times).
I’d suggest waiting for DISPATCH_TIME_FOREVER (assuming you want it to really wait for it to finish).
Also, if these are properties (which I’m guessing they are on the basis of the underscores), then using self.env rather than self->_env is safer, as it won’t crash if self is nil, but rather will just return nil.
I must confess that this still doesn’t look right (e.g. if updateFromTable is asynchronous already, why bother dispatching this asynchronously to _repQueue; if it is synchronous, then again, why dispatch this asynchronously only to wait for it). But it’s impossible to comment further without seeing the updateFromTable implementation.
Or, better, make the method asynchronous:
- (void)processWithCompletion:(void (^)(NSString *))callback {
typeof(self) __weak weakSelf = self;
dispatch_async(_repQueue, ^{
typeof(self) strongSelf = weakSelf;
if (!strongSelf) { return; }
[strongSelf updateFromTable:[strongSelf->_env table] env:strongSelf->_env callback:^{
NSString *ret = [some op .. ];
callback(ret);
}];
});
}

Related

Obj-C return to a block from a delegate method?

I'm writing a mac app that runs its own web server, using the GCDWebServer library (https://github.com/swisspol/GCDWebServer). My app delegate handles GET requests like so:
__weak typeof(self) weakSelf = self;
[webServer addDefaultHandlerForMethod:#"GET"
requestClass:[GCDWebServerRequest class]
processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {
return [weakSelf handleRequest:request];
}];
And then the handleRequest method returns the response data, something like:
return [GCDWebServerDataResponse responseWithHTML:#"<html><body><p>Hello World!</p></body></html>"];
So far so good. Except now I want the handleRequest method to use NSSpeechSynthesizer to create an audio file with some spoken text in it, and then wait for the speechSynthesizer:didFinishSpeaking method to be called before returning to the processBlock.
// NSSpeechSynthesizerDelegate method:
- (void)speechSynthesizer:(NSSpeechSynthesizer *)sender didFinishSpeaking:(BOOL)success
{
NSLog(#"did finish speaking, success: %d", success);
// return to processBlock...
}
Problem is, I have no idea how to do this. Is there a way to return from the speechSynthesizer:didFinishSpeaking method into the processBlock defined above?
You need to run the speech synthesizer on a separate thread with its own run loop, and use a lock to allow your request thread to wait for the operation to complete on the speech thread.
Assuming the web server maintains its own thread(s) and runloop, you can use your app's main thread to run the speech synthesizer, and you can use NSCondition to signal completion to the web response thread.
A basic (untested) example (without error handling):
#interface SynchroSpeaker : NSObject<NSSpeechSynthesizerDelegate>
- (id)initWithText:(NSString*)text outputUrl:(NSURL*)url;
- (void)run;
#end
#implementation SynchroSpeaker
{
NSCondition* _lock;
NSString* _text;
NSURL* _url;
NSSpeechSynthesizer* _synth;
}
- (id)initWithText:(NSString*)text outputUrl:(NSURL*)url
{
if (self = [super init])
{
_text = text;
_url = url;
_lock = [NSCondition new];
}
return self;
}
- (void)run
{
NSAssert(![NSThread isMainThread], #"This method cannot execute on the main thread.");
[_lock lock];
[self performSelectorOnMainThread:#selector(startOnMainThread) withObject:nil waitUntilDone:NO];
[_lock wait];
[_lock unlock];
}
- (void)startOnMainThread
{
NSAssert([NSThread isMainThread], #"This method must execute on the main thread.");
[_lock lock];
//
// Set up your speech synethsizer and start speaking
//
}
- (void)speechSynthesizer:(NSSpeechSynthesizer *)sender didFinishSpeaking:(BOOL)success
{
//
// Signal waiting thread that speaking has completed
//
[_lock signal];
[_lock unlock];
}
#end
It's used like so:
- (id)handleRequest:(id)request
{
SynchroSpeaker* speaker = [[SynchroSpeaker alloc] initWithText:#"Hello World" outputUrl:[NSURL fileURLWithPath:#"/tmp/foo.dat"]];
[speaker run];
////
return response;
}
GCDWebServer does run into its own threads (I guess 2 of them) - not in the main one. My solution needed to run code in Main Thread when calling the ProcessBlock.
I found this way that suits my needs:
First declare a weak storage for my AppDelegate: __weak AppDelegate *weakSelf = self;. Doing so I can access all my properties within the block.
Declare a strong reference to AppDelegate from within the block like so: __strong AppDelegate* strongSelf = weakSelf;
Use NSOperationQueue to align the operation on mainThread:
[[NSOperationQueue mainQueue] addOperationWithBlock:^ {
//Your code goes in here
NSLog(#"Main Thread Code");
[strongSelf myMethodOnMainThread];
}];
In this way myMethodOnMainThread surely will run where it's supposed to.
For sake of clarity I quote my relevant code section:
webServer = [[GCDWebServer alloc] init];
webServer.delegate = self;
__weak AppDelegate *weakSelf = self;
// Add a handler to respond to GET requests
[webServer addDefaultHandlerForMethod:#"GET"
requestClass:[GCDWebServerRequest class]
asyncProcessBlock:^(GCDWebServerRequest* request, GCDWebServerCompletionBlock completionBlock) {
__strong AppDelegate* strongSelf = weakSelf;
[[NSOperationQueue mainQueue] addOperationWithBlock:^ {
//Your code goes in here
NSLog(#"Main Thread Code");
[strongSelf myMethodOnMainThread];
}];
GCDWebServerDataResponse* response = [GCDWebServerDataResponse responseWithJSONObject:packet];
completionBlock(response);
}];
GCWebServer supports fully asynchronous responses as of version 3.0 and later [1].
[webServer addDefaultHandlerForMethod:#"GET"
requestClass:[GCDWebServerRequest class]
asyncProcessBlock:^(GCDWebServerRequest* request, GCDWebServerCompletionBlock completionBlock) {
// 1. Trigger speech synthesizer on main thread (or whatever thread it has to run on) and save "completionBlock"
// 2. Have the delegate from the speech synthesizer call "completionBlock" when done passing an appropriate response
}];
[1] https://github.com/swisspol/GCDWebServer#asynchronous-http-responses

Is it safe to dispatch_async in dealloc?

I'm having a random EXC_BAD_ACCESS KERN_INVALID_ADDRESS, but I can't point out the source. However, I'm wondering if this might be it:
I have an audio_queue created like this:
_audio_queue = dispatch_queue_create("AudioQueue", nil);
which I use to create and access an object called _audioPlayer:
dispatch_async(_audio_queue, ^{
_audioPlayer = [[AudioPlayer alloc] init];
});
The audio player is owned by a MovieView:
#implementation MovieView
{
AudioPlayer *_audioPlayer
}
Then, in the dealloc method of MovieView, I have:
- (void)dealloc
{
dispatch_async(_audio_queue, ^{
[_audioPlayer destroy];
});
}
Is this acceptable? I'm thinking that by the time the block is called, the MovieView would have already been deallocated, and when trying to access the _audioPlayer, it no longer exists. Is this the case?
My crash report only says:
MovieView.m line 0
__destroy_helper_block_
Your bug is in the ivar access. This is due to how ivars work in ObjC: the -dealloc above is equivalent to
- (void)dealloc
{
dispatch_async(self->_audio_queue, ^{
[self->_audioPlayer stopPlaying];
});
}
This can break because you end up using self after it is dealloced.
The fix is something like
- (void)dealloc
{
AVAudioPlayer * audioPlayer = _audioPlayer;
dispatch_async(audio_queue, ^{
[audioPlayer stopPlaying];
});
}
(It is frequently not thread-safe to explicitly or implicitly (via ivars) reference self in a block. Sadly, I don't think there is a warning for this.)
If this is the cause, the you could use dispatch_sync
- (void)dealloc
{
dispatch_sync(_audio_queue, ^{
[_audioPlayer stopPlaying];
});
}
I haven't tested this

Wait for two async methods to complete

I'd like to init a model, let the model do some async stuff and present a new viewcontroller once completed. But how do i wait for the two async methods to be completed and how do I setup the callback method?
Pseudocode
In my StartViewController.m:
-(void)openArticle
{
article = [Article initWithObject:someObject];
article.callback = changeView;
}
-(void)changeView
{
[self presentViewController:someController];
}
In my ArticleModel.m:
-(void)initWithObject:someObject
{
[self loadImage]
[self geoCode]
}
-(void)loadImage
{
runAsyncMethod: success:^() // This one is actually a AFNetworking setImageWithURLRequest
}
-(void)geoCode
{
runAnotherAsyncMethod: success:^() // This one is actually a geocodeAddressString operation
}
You can achieve this using dispatch_groups
- (void)initWithObject:(id)someObject
{
self = [super init];
if (self) {
self.dispatch_group = dispatch_group_create();
[self loadImage]
[self geoCode]
dispatch_group_notify(self.dispatch_group, dispatch_get_main_queue(), ^{
NSLog(#"Push new view controller");
});
}
return self;
}
- (void)loadImage
{
dispatch_group_enter(self.dispatch_group);
__weak __typeof(self) weakSelf = self;
runAsyncMethod: success:^{
__typeof(weakSelf) strongSelf = weakSelf;
if (strongSelf.dispatch_group) {
dispatch_group_leave(strongSelf.dispatch_group); // You need to ensure that this is called in both success and failure
}
}
}
- (void)geoCode
{
dispatch_group_enter(self.dispatch_group);
__weak __typeof(self) weakSelf = self;
runAnotherAsyncMethod: success:^{
__typeof(weakSelf) strongSelf = weakSelf;
if (strongSelf.dispatch_group) {
dispatch_group_leave(strongSelf.dispatch_group);
}
}
}
You do not wait. If you wait, it isn't asynchronous! You would be losing the entire point of asynchronous if you were to wait.
What you do is, when your success handler is called, you step out to the main thread (just in case you got called back on a background thread) and now do whatever you need to do. In other words, you just let your success handler get called whenever it happens to get called.
In your case, you might like to chain the things you want to do:
Call loadImage
In its callback, call geoCode
In its callback, step out to the main thread and present the new view controller.
You can use dispatch_group so that when a method is over, it just leaves the group. I use a similar code myself and it works like a charm.
- (void)initWithObject:someObject {
// Create a dispatch group
dispatch_group_t group = dispatch_group_create();
[self loadImageWithDispatchGroup:group];
[self geoCodeWithDispatchGroup:group];
// Here we wait for all the requests to finish
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// Do whatever you need to do when all requests are finished
});
}
- (void)loadImageWithDispatchGroup:(dispatch_group_t)group {
dispatch_group_enter(group);
runAsyncMethod: success:^() // This one is actually a AFNetworking setImageWithURLRequest
// In your success or failure AFNetworking method, call this as soon as the request ended
dispatch_group_leave(group);
}
- (void)geoCodeWithDispatchGroup:(dispatch_group_t)group {
dispatch_group_enter(group);
runAnotherAsyncMethod: success:^() // This one is actually a geocodeAddressString operation
// In your success async geocode callback method, call this as soon as the request ended
dispatch_group_leave(group);
}
I do not known your needs but native GCD way to wait several asynch tasks is
void dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);
https://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html#//apple_ref/c/func/dispatch_barrier_async

Synchronizing a Block within a Block?

I'm playing around with blocks in Objective-C, trying to come up with a reusable mechanism that will take an arbitrary block of code and a lock object and then execute the block of code on a new thread, synchronized on the provided lock. The idea is to come up with a simple way to move all synchronization overhead/waiting off of the main thread so that an app's UI will always be responsive.
The code I've come up with is pretty straightforward, it goes like:
- (void) executeBlock: (void (^)(void))block {
block();
}
- (void) runAsyncBlock: (void (^)(void))block withLock:(id)lock {
void(^syncBlock)() = ^{
#synchronized(lock) {
block();
}
};
[self performSelectorInBackground:#selector(executeBlock:) withObject:syncBlock];
}
So for example, you might have some methods that go like:
- (void) addObjectToSharedArray:(id) theObj {
#synchronized(array) {
[array addObject: theObj];
}
}
- (void) removeObjectFromSharedArray:(id) theObj {
#synchronized(array) {
[array removeObject: theObj];
}
}
Which works fine, but blocks the calling thread while waiting for the lock. These could be rewritten as:
- (void) addObjectToSharedArray:(id) theObj {
[self runAsyncBlock:^{
[array addObject: theObj];
} withLock: array];
}
- (void) removeObjectFromSharedArray:(id) theObj {
[self runAsyncBlock: ^{
[array removeObject: theObj];
} withLock:array];
}
Which should always return immediately, since only the background threads will compete over the lock.
The problem is, this code crashes after executeBlock: without producing any output, error message, crash log, or any other useful thing. Is there something fundamentally flawed in my approach? If not, any suggestions with respect to why this might be crashing?
Edit:
Interestingly, it works without crashing if I simply do:
- (void) runAsyncBlock: (void (^)(void))block withLock:(id)lock {
void(^syncBlock)() = ^{
#synchronized(lock) {
block();
}
};
syncBlock();
}
But of course this will block the calling thread, which largely defeats the purpose. Is it possible that blocks do not cross thread boundaries? I would think not, since that would largely defeat the purpose of having them in the first place.
remember to call [block copy] otherwise it is not correctly retained because block are created on stack and destroyed when exit scope and unless you call copy it will not move to heap even retain is called.
- (void) runAsyncBlock: (void (^)(void))block withLock:(id)lock {
block = [[block copy] autorelease];
void(^syncBlock)() = ^{
#synchronized(lock) {
block();
}
};
syncBlock = [[syncBlock copy] autorelease];
[self performSelectorInBackground:#selector(executeBlock:) withObject:syncBlock];
}

Objective C - block question?

I have the following method
+ (NSString*)getMeMyString
{
NSString *result;
dispatch_async(dispatch_get_main_queue(), ^{
result = [ClassNotThreadSafe getString];
});
return result;
}
How can i make the block to do it's job synchronously, so that it doesn't return the result before it was retreived?
You are calling dispatch_async which dispatches your block asynchronously. Try using dispatch_sync or dispatch_main if your goal is to block the main thread.
+ (NSString*)getMeMyString
{
__block NSString *result;
dispatch_sync(dispatch_get_main_queue(), ^{
result = [ClassNotThreadSafe getString];
});
return result;
}
Grand Central Dispatch Reference
Use dispatch_sync instead of dispatch_async - then the current thread will be blocked until the block has finished executing on the main thread.
Since it seems like you want to perform a method on a different thread and get a return value, why don't you use an NSInvocation?
SEL theSelector;
NSMethodSignature *aSignature;
NSInvocation *anInvocation;
theSelector = #selector(getString);
aSignature = [ClassNotThreadSafe instanceMethodSignatureForSelector:theSelector];
anInvocation = [NSInvocation invocationWithMethodSignature:aSignature];
[anInvocation setSelector:theSelector];
NSString *result;
[anInvocation performSelectorOnMainThread:#selector(invoke) withObject:nil waitUntilDone:YES];
[anInvocation getReturnValue:result];