If I put a try catch and finally inside an async GCD call the finally generally seems to not get executed and I am not sure about the catch either, seems to execute some of the time.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
#try {
[self methodThatAlwaysThrowsAnException];
}#catch (NSException *exc) {
NSLog(#"Caught the Exception %#",exc);
}#finally{
NSLog(#"Should always execute");
}
});
Does anyone know why this is?
Consequently I put the finally call outside of dispatch_async but I would prefer to know that my try was fully executed.
Try to avoid #try/#catch for control-flow operations.
Also, your code sample works fine for me. The #finally block is always executed, as is the #catch block if there was an exception thrown.
Related
I'm implementing a mic plugin for a game and since the [capture_session startRunning] function is a long call, I'm wrapping it in an async call, but it is still laggy.
Commenting the code solves the lag, so I'm pretty sure this is the chunk that causes it.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[capture_session startRunning];
is_recording = true;
NSMutableDictionary *event = [Utils newEvent:EVENT_NAME];
event[PHASE_KEY] = #"started";
event[IS_ERROR_KEY] = #((bool)false);
[Utils dispatchEvent:lua_listener event:event];
});
Btw, I don't know much the language so I could be doing some very silly things here.
Really appreciate any help!
try this?
dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0), ^{
...
NSLog(#"current thread ---%#", [NSThread currentThread]);
});
You use concurrent queue and async method, those code you put in block should be run in a new thread.
I am using a multi threaded environment in my app, I need to constantly access sqlite db in order to update my views and also update my DB with server data via multiple background threads. Right now I am using FMDB for DB interaction but still getting DB locked problem.
FMDatabaseQueue *_queue = [FMDatabaseQueue databaseQueueWithPath:databasePath];
NSOperationQueue *_writeQueue = [NSOperationQueue new];
[_writeQueue setMaxConcurrentOperationCount:1];
NSRecursiveLock *_writeQueueLock = [NSRecursiveLock new];
[_writeQueue addOperationWithBlock:^{
BOOL tryLock = NO;
#try {
[_writeQueueLock lock];
tryLock = YES;
[_queue inDatabase:^(FMDatabase *db) {
#try {
[db logsErrors];
[db executeUpdate:updateSQL];
}
#catch (NSException *exception) {
}
#finally {
}
}];
}
#catch (NSException *exception) {
NSLog(#"Error while inserting data saveLocation inside operation queue. %#", exception.description);
}
#finally {
if (tryLock) {
[_writeQueueLock unlock];
}
}
}];
This what I am doing every time I insert data and similar way when I read data from DB as I am locking, Process should not be able to access DB until one thread finishes. I don't know what is wrong please help me out.
Whenever multiple threads try to access same table to read and write or two threads wants to write on same table of same db sqlite produces db locked signal so to resolve this you need Locks
NSRecursiveLock *_writeQueueLock = [NSRecursiveLock new];
as you've added in your code, but this won't help you much as you're trying to craete a new lock every time you insert.
This lock should be a single object for all your blocking calls to DB like insert, update, delete etc.
Try creating a singleton instance of lock, This should help:
static FMDatabaseQueue *_queue;
static NSOperationQueue *_writeQueue;
static NSRecursiveLock *_writeQueueLock;
+(SomeDBClass*)getSharedInstance{
if (!sharedInstance) {
sharedInstance = [[super allocWithZone:NULL]init];
_queue = [FMDatabaseQueue databaseQueueWithPath:databasePath];
_writeQueue = [NSOperationQueue new];
[_writeQueue setMaxConcurrentOperationCount:1];
_writeQueueLock = [NSRecursiveLock new];
}
return sharedInstance;
}
Now once your objects created you can call your insert, update, delete method on these queue and locks like:
[_writeQueue addOperationWithBlock:^{
BOOL tryLock = NO;
#try {
[_writeQueueLock lock];
tryLock = YES;
[_queue inDatabase:^(FMDatabase *db) {
#try {
[db logsErrors];
[db executeUpdate:updateSQL];
}
#catch (NSException *exception) {
}
#finally {
}
}];
}
#catch (NSException *exception) {
NSLog(#"Error while inserting data saveLocation inside operation queue. %#", exception.description);
}
#finally {
if (tryLock) {
[_writeQueueLock unlock];
}
}
}];
You can also refer this for better understanding, Hope this helps and I am new to the stack so please be little bit forgiving Thanks.
Using FMDatabaseQueue completely eliminates the need for any other locking mechanism. Adding another locking mechanism is only going to complicate the issue further.
If you are getting messages about the database being "locked", it because either:
you have multiple FMDatabase/FMDatabaseQueue objects out there; or
you're calling inDatabase from within another inDatabase call.
You should have one FMDatabaseQueue object which is shared amongst all of the threads and you need to make sure that none of your functions called with a inDatabase block calls something else that itself tries another inDatabase call.
I wanna check the UITextField is String or number by using try catch.
But it seems doesn't work. Here is my code:
- (IBAction)add {
#try {
double firstNumber = self.firstNumber.text.doubleValue;
double secondNumber = self.secondNumber.text.doubleValue;
Calculator *calcu = [[Calculator alloc] initWithFirstNumber:firstNumber andSecondNumber:secondNumber andOperation:#"+"];
self.result.text = calcu.calculateTwoNumber;
}
#catch (NSException *exception) {
self.result.text = #"Please enter right number!";
}
#finally {
}
}
Follow code:
#try {
self.labelName.text=[arrName ObjectAtIndex:indexPath.row];
}
#catch (NSException *exception) {
NSLog(#"Something missing...");
}
#finally {
}
What Claus Bönnhoff wrote in the comments cannot be overemphasized: Objective-C is not Java or C#.
The accepted way to use exceptions in Obj-C is for unrecoverable errors, not simple flow control.
The answer to your question, then, is that exceptions should be used very rarely. In several years of iOS development, I haven't used them a single time. I also have not come accross them in anyone else's code.
I have, however, encountered exceptions thrown by the Obj-C runtime, which I suppose gives some indication of what their role might be.
I have a code for fetching json. It works perfectly fine, when my device is connected to internet, but it crashes if there is no internet connection.
I have surrounded that particular line of code with try / catch block, but it doesn't seem to do the trick.
Of course, I can do a workaround, and first check if there is internet connection and then call the method I need, but I want to understand this.
Why #catch isn't triggered in this case, and what to do to handle this exception in this case?
Here is the code:
#try {
NSError *error;
NSMutableDictionary* json = [NSJSONSerialization
JSONObjectWithData:_jsonData
options:NSJSONReadingMutableContainers|NSJSONReadingMutableLeaves
error:&error];
...
#catch (NSException *exception) {
[_indicator stopAnimating];
_indicator.hidden = YES;
[self popUp];
}
So, the exception occurs when trying to populate json dictionary.
Your JSON data _jsonData seems to be obtained before try~catch block, and then the source of the issue should be out of the block. Then you need to find out where the data is obtained from the internet, and install the try~catch block at there.
In Xcode, when I'm trying to add more than 5 images to my library, it gives me the following error:
Error Domain=ALAssetsLibraryErrorDomain Code=-3301 "Write busy" UserInfo=0xa706aa0 {NSLocalizedRecoverySuggestion=Try to write again, NSLocalizedFailureReason=There was a problem writing this asset because the writing resources are busy., NSLocalizedDescription=Write busy, NSUnderlyingError=0xa770110 "Write busy"}
In order to solve this problem, I figured out threads would solve my problems. The documentation states that I can use POSIX threads or NSThreads. When I try using POSIX threads, I set my threads to be joinable, and I'm creating a void * function:
void * myFunc (void * image)
{
UIImageWriteToSavedPhotosAlbum((__bridge UIImage *)(image),self,nil,nil);
pthread_exit(NULL);
return NULL;
}
I am also waiting for the thread to end. But still only 5 images are written.
I've tried using NSThreads and did:
[self performSelectorOnMainThread:#selector(myFunc:) withObject:image waitUntilDone:YES];
But still it doesn't work.
Is there an answer to my problem? It's crucial to my work.
Thanks.
Edit:
Tried dispatch_async too. Is it wrong?
dispatch_queue_t myQueue = dispatch_queue_create("com.cropr.myqueue", 0);
for (UIImage * image in images) {
dispatch_async(myQueue, ^{
[self.library saveImage:image toAlbum:#"Cropr" withCompletionBlock:^(NSError *error) {
if (error!=nil) {
NSLog(#"Big error: %#", [error description]);
}
}];
});
}
What do I need to add?
You may try to write all your images subsequently, instead of simultaneously. The following code utilizes ALAssetsLibrary, and implements an "asynchronous loop" which invokes a number of asynchronous methods in sequence.
typedef void (^completion_t)(id result);
- (void) writeImages:(NSMutableArray*)images
completion:(completion_t)completionHandler {
if ([images count] == 0) {
if (completionHandler) {
// Signal completion to the call-site. Use an appropriate result,
// instead of #"finished" possibly pass an array of URLs and NSErrors
// generated below in "handle URL or error".
completionHandler(#"finished");
}
return;
}
UIImage* image = [images firstObject];
[images removeObjectAtIndex:0];
[self.assetsLibrary writeImageToSavedPhotosAlbum:image.CGImage
orientation:ALAssetOrientationUp
completionBlock:^(NSURL *assetURL, NSError *error)
{
// Caution: check the execution context - it may be any thread,
// possibly use dispatch_async to dispatch to the main thread or
// any other queue.
// handle URL or error
...
// next image:
[self writeImages:images completion:completionHandler];
}];
}
Usage:
[foo writeImages:[foo.images mutableCopy] completion:^(id result){
// Caution: check the execution context - it may be any thread
NSLog(#"Result: %#", result);
}];
I'd recommend using an NSOperationQueue and play with the value of maxConcurrentOperationCount. This way you can control the number of simultaneous writes to the library, and not overwhelm it.
If you use threads, or even GCD, you'd need to implement this logic yourself. More code --> more chance of introducing a bug.
Dispatch_async is something to do in background , so I put your for{} and function call inside the dispatch_async body
so putting for inside the dispatch async will store your imaged in the album,like just running for. but on seperate thread.
dispatch_queue_t myQueue = dispatch_queue_create("com.cropr.myqueue", 0);
dispatch_async(myQueue, ^{
for (UIImage * image in images)
UIImageWriteToSavedPhotosAlbum((__bridge UIImage *)(image),self,nil,nil);
});
}
You can also try this. i think will be better, watch if it works , then add what you want to handle the errors.
Also i think here is your desired answer : iOS: dispatch_async and UIImageWriteToSavedPhotosAlbum