To log any message on file I am using writeData method of NSFileHandle. Sometimes this method throws an exception but I can not handle it because code is written in swift.
Is there any work around ?
I have tried this :
I have tried this : NS_INLINE NSException * _Nullable tryBlock(void(^_Nonnull tryBlock)(void)) {
#try {
tryBlock();
}
#catch (NSException *exception) {
return exception;
}
return nil;
Related
I have the following NSFetchedResultsController extension:
extension NSFetchedResultsController
{
func tryObjectAtIndex(_ indexPath: IndexPath) throws -> AnyObject // ERROR HERE
{
do
{
try ObjC.catchException
{
return self.object(at: indexPath) // CAUSE
}
}
catch
{
print("An error ocurred: \(error)")
}
}
}
in which ObjC is an Objective-C class (from here). Here's the .h:
#import <Foundation/Foundation.h>
#interface ObjC : NSObject
+ (BOOL)catchException:(void(^)())tryBlock error:(__autoreleasing NSError **)error;
#end
And the .m:
#implementation ObjC
+ (BOOL)catchException:(void(^)())tryBlock error:(__autoreleasing NSError **)error
{
#try
{
tryBlock();
return YES;
}
#catch (NSException *exception)
{
*error = [[NSError alloc] initWithDomain:exception.name code:0 userInfo:exception.userInfo];
return NO;
}
}
#end
At tryObjectAtIndex the error Extension of a generic Objective-C class cannot access the class's generic parameters at runtime appears.
The only answer to related question 'How to write an extension for NSFetchedResultsController in Swift 4' suggests to add #objc in front of the function. But in the above code this does not make any difference.
Calling self.object(at:) causes this trouble. But actually, without the Objective-C exception handling, so just return self.object(at: indexPath) as the body of the function, the error does not occur.
How to I resolve this?
IMPORTANT: I'm at Xcode 8.3.2 and can't update at the moment (as it's a legacy project).
I am working on some API (Crittercism) to report handled exceptions in the client to server.
The client API takesNSException as the input parameter. I have to add some application context info string(NSString) also to theNSException before calling the API.
How I can do it using Objective-C.
NSString* appContextString;
NSString *test = #"test";
unichar a;
int index = 5;
#try {
a = [test characterAtIndex:index];
}
#catch (NSException *exception) {
// add app context to exception before reporting to Crittercism.
[Crittercism logHandledException:exception];
}
I have to append appContextString to exception.
You could build a new NSException object from attributes of the old one, but that seems very messy. As you are just logging the handled exception, I would simply log the "app context" before that:
#try {
a = [test characterAtIndex:index];
}
#catch (NSException *exception) {
NSString *appContext = #"...";
[Crittercism leaveBreadcrumb:appContext];
[Crittercism logHandledException:exception];
}
You have to copy it. This can be done easily. An instance of NSExeption has three important properties:
name
reason
user info
When copying it, you can add a string to the user info dictionary:
NSMutableDictionary *userInfo = [exception.userInfo mutableCopy];
userInfo[#"YourPrivateKey"] = contextString;
NSException *extendedException = [NSException exceptionWithName:exception.name reason:exception.reason userInfo:userInfo];
I think as a caveat that you will lose the call stack. You can read that and put it in the user info dictionary, too. I do it a similar way on Objective-Cloud.
userInfo[#"CallStackSymbols2] = exception.callStackSymbols;
Analogous with call stack return addresses.
I do not think that this is very nice, because the call stack becomes a part of the exceptions's user info instead of the exception itself. For me this is no caveat, because I sent the exception as JSON, therefore the call stack as JSON object. I cannot say, whether this is a problem for you.
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 simple wrapper for NSLogv. It works fine, except throws an exception if there are too many placeholders in the format string. I would like to catch that exception, but this #try block doesn't work. Why?
- (void)error:(NSString *)formatString, ...;
{
#try {
va_list arglist;
va_start(arglist, formatString);
formatString = [NSString stringWithFormat:#"ERROR: %#", formatString];
NSLogv(formatString, arglist);
va_end(arglist);
}
#catch (NSException *exception) {
// Handle exception ...
}
}
Here is an example that throws an exception:
[[MYLogger error:#"%# %#", value];
#try catches exceptions. You are trying to catch a signal.
My advice: Don't even try.
I want to integrate in my iPad application a way to monitor the user activity and especially the exceptions that occurred and triggered the application to stop, something like the bug report of Apple but for the mobile clients.
I tried to encapsulate the main action (main.m) between #try and #catch blocks, but the exception is not thrown until there, and I just can't add such blocks everywhere in my code. Neither the delegate method applicationWillTerminate is not called, the application is just brutally stopped without any notification.
Any ideas on this ?
It works for me in main.m
int main(int argc, char *argv[]) {
#autoreleasepool {
int retVal = 0;
#try {
retVal = UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
#catch (NSException *exception) {
NSLog(#"Exception: %#", exception);
[exception raise];
}
return retVal;
}
}
P.S.
Another tricky way : EXC_BAD_ACCESS automatic handling
And example of NSUncaughtExceptionHandler