objective-c exceptions not caught in swift 3 do catch handler - try-catch

I use a objective-c library in my swift code base. The library may throw an exception. Unfortunately, the exception does not get caught within Swift 3. How do I work around this issue?

In general it is no good idea to use Objective-C exception handling, but sometimes it's neccessary. ;)
Swift exception handling is totally different from Objective-C. You can't catch Objective-C exceptions in Swift directly. Instead, you should write an Objective-C wrapper, e. g.:
#implementation NSDictionary(NoException)
- (id)noExceptionValueForKey:(NSString *)inKey {
#try {
return [self valueForKey:inKey];
}
#catch(NSException *anException) {
// More exception handling if neccessary
return nil;
}
}
#end
From Swift you should call noExceptionValueForKey: instead of valueForKey:.

Related

Strange Xcode 4.6 related bug

The error we're getting is something like this:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[_CDSnapshot_Widget_ unlockObjectStore]: unrecognized selector sent to instance 0x1c5a4350'
sometimes the Widget class is sent that selector, sometimes it's __NSCFString, sometimes the crash is this:
[NSManagedObjectContext unlockObjectStore]: message sent to deallocated instance 0x1ec658c0
I think I've narrowed down where the issue is occurring, but I have no idea why this code would be causing it.
Here's an example structure of our data access classes:
// DataController.m
static NSPersistentStoreCoordinator *_persistentStoreCoordinator;
static NSManagedObjectModel *_managedObjectModel;
static NSManagedObjectContext *_mainManagedObjectContext;
#implementation DataController
- (NSManagedObjectContext *) privateManagedObjectContext {
return [DataController buildManagedObjectContextForConcurrencyType:NSPrivateQueueConcurrencyType];
}
- (NSManagedObjectContext *) defaultManagedObjectContext {
return [self managedObjectContextForConcurrencyType: self.defaultConcurrencyType];
}
- (NSManagedObjectContext *) managedObjectContextForConcurrencyType: (NSManagedObjectContextConcurrencyType) type {
if (type == NSMainQueueConcurrencyType)
return [self mainManagedObjectContext];
else if (type == NSPrivateQueueConcurrencyType)
return [self privateManagedObjectContext];
return nil;
}
// calling _dataController.defaultManagedObjectContext from within the Widgets class
// essentially calls this method for a new context using NSPrivateQueueConcurrencyType as
// the type parameter
+ (NSManagedObjectContext *) buildManagedObjectContextForConcurrencyType: (NSManagedObjectContextConcurrencyType) type {
NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType: type];
[context setUndoManager: nil];
[context setMergePolicy: NSMergeByPropertyObjectTrumpMergePolicy];
[context setPersistentStoreCoordinator: _persistentStoreCoordinator];
return context;
}
#end
and our widgets class
// Widgets.m
static DataController *_dataController;
#implementation Widgets
+ (void) initialize {
_dataController = [[DataController alloc] init];
}
+ (NSArray *)certainWidgets {
return [self certainWidgetsInManagedObjectContext:_dataController.defaultManagedObjectContext];
}
+ (NSArray *) certainWidgetsInManagedObjectContext: (NSManagedObjectContext *) context {
// boiler plate CoreData fetching code
}
#end
This is an example of code used to fetch widgets
dispatch_async(dispatch_get_global_queue(0, 0), ^{
for (Widget *w in [Widgets certainWidgets]) {
if ([w.isValid intValue]) {
// do something extraoridarily fantastic with the widget
}
}
});
This only happens in Xcode 4.6, Release mode (not in Debug). We're not seeing anything in the Xcode 4.6 release notes that would give us a clue as to what's happening.
I suspect the issue has to do with how we've structured our data access class (DataController) coupled with the fact that we're using class methods to handle all data access within the Widgets class. The reason for my suspicion is that when we remove the class methods from the Widgets class and make them instance methods instead, get rid of the +initialize method, and set up an NSManagedObjectContext for each instance of the Widgets class, the problem seems to go away.
Just to clarify, I think I've fixed the issue, but I'm not comfortable pushing out the fix until I understand why the above mentioned changes fix it. It looks like there's some sort of memory issue or bad programming paradigm that we're not catching onto. Any pointers?
Turns out this is a bug related to CLang optimizations. We've found a few other people experiencing the same problem. Turning all optimizations off seems to fix the issue.
It happens, for us, when creating a static data management instance, spawning a new thread, and using that static instance to create a managed object context.
Our fix will be to rethink our data management paradigm.
If you're using this screen over your app, or it appears several time & crashes on second one than check your memory management over this screen. It may be the case, when you're holding in memory several copies of screen. Check notification centre removal observer for example.

why can't i write this camel route?

from("e1")
.split()
.method("bean", "m1")
.to("e2")
.end()
.split()
.method("bean", "m2")
.to("e3");
The compiler complains about the 2nd to. The reason is that for some reason, it thinks the second split returns ExpressionCaluse rather than ExpressionClause<SplitDefinition>, which causes the following method return type to be Object rather than SplitDefinition.
I tried it in Eclipse, and first I got the same result as you (with the eclipse code completion showing an error). Then I rewrote the route (e.g. splitting it up with assignments to
ProcessorDefinition pd = from("e1")....
pd.split()...
Then, back to the original code, so finally Eclipse got the idea correct and the error marker disappeared. I don't know if you was trying eclipse too?
#Override
public void configure() throws Exception {
from("e1")
.split()
.method("bean", "m1")
.to("e2")
.end()
.split().method("bean", "m2")
.to("e3");
}
I mean, it should work. The signature of split() in ProcessorDefinition is correct:
public ExpressionClause<SplitDefinition> split()
I guess this is a glitch somewhere in my dev. env. and probably yours too.. or something. Odd, anyway.

MonoTouch - WCF Services made by Silverlight tool - Can't catch exceptions

Using the Silverlight service generator a service class is created:
slsvcutil.exe http://localhost/zzz/zzzz.svc?wsdl
/namespace:"*,General" /d:z:\desktop /noConfig /ser:DataContractSerializer
This class then is created and the async methods called.
Even with all calls and constructions wrapped in Exception try/catches, we can not catch errors like "System.ServiceModel.EndpointNotFoundException"
We have the exact same code running in Silverlight clients, and errors are caught in try/catch blocks.
Question: Is there another place/method I need to use in order to catch WCF errors when consuming in MonoTouch?
I don't know if I understood your question well... :)
In my opinion, in the handler for the async request, check if the error is null or not.
if(e.Error != null)
{
// insert code here to fix the error
// in a similar way you do with catch block
}
else
{
// normal execution
}
Hope it helps you!! Best regards.
This appears to be a bug. The framework team is fixing it.

How to catch an exception thrown from an event?

I am porting TCPClient into Silverlight and I see that the BeginConnect can throw a SocketException somehow from the asynchronous process.
In silverlight there is a Completed event for the ConnectAsync function which supplies a SocketError in it's SocketAsyncEventArgs parameter.
I am throwing a new SocketException whenever the socket fails to connect from the method my implementation of TCPClient hooked into the Completed event.
The problem lays here:
try
{
var ar = client.BeginConnect(...);
// Do stuff
client.EndConnect(ar);
}
catch(SocketException e)
{
// Handle exception here
}
The exception won't be catched here due to the fact that it is thrown from an event? Or maybe it's because the event is executed on another thread? I'm not sure. In any case the exception is not caught.
Well, this doesn't answer your question directly, but if no one has a better solution, you can create your own thread and do a Connect instead of a BeginConnect. Then, you should be able to catch the exception.
You should do a lambda to capture the errors as shown here:
http://social.msdn.microsoft.com/Forums/hu-HU/csharpgeneral/thread/0fbe2ebd-a576-4ac5-a1ed-a5d13d0cd9c8

Dispatcher.Run vs Dispatcher.PushFrame

I have a non-ui thread that I need to pump messages on.
The normal way to do this would involve a call Dispatcher.Run() in the thread proc of my thread.
I'd like to modify this to make it more robust with regard to unhandled exceptions.
My first cut is:
for (;;)
{
var frame = new DispatcherFrame();
try
{
Dispatcher.PushFrame(frame);
break;
}
catch (Exception e)
{
frame.Continue = false;
Log("ThreadProc caught exception:\n{0}", e);
}
}
This code works and allows the dispatcher to continue pumping messages after an exception.
Does anyone know of any potential problems with this approach?
I find using a dispatcherframe can give some problems when using it with a ui thread - for example problems with focus - I think your scenario will be fine.
Have you tried catching it with:
Application.DispatcherUnhandledException
or
Dispatcher.UnhandledException
You could also try that and set Handled=true to make it continue.

Resources