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.
Related
Most times I launch the app, the test-to-speech audio and speech recognition work perfectly. But sometimes I launch it and it crashes when first starting speech recognition. It seems to get on a roll and crash several launches in a row, so it is a little bit consistent, once it gets into one of its 'moods' :)
The recognition starts after a TTS introduction and at the same time as TTS says 'listening' - therefore both are active at once. Possibly the audio takes a few milliseconds to change over and gets crashy, but I am not clear how this works or how to prevent it.
I see the following error:
[avae] AVAEInternal.h:70:_AVAE_Check: required condition is false:
[AVAudioIONodeImpl.mm:911:SetOutputFormat: (format.sampleRate == hwFormat.sampleRate)]
*** Terminating app due to uncaught exception 'com.apple.coreaudio.avfaudio',
reason: 'required condition is false: format.sampleRate == hwFormat.sampleRate'
I have put some try-catches in, just to see if it prevents this error and it doesn't. I also added a tiny sleep which also made no difference. So I am not even clear which code is causing it. If I put a breakpoint before the removeTapOnBus code, it does not crash until this line executes. If I put the breakpoint on the installTapOnBus line it does not crash until that line. And if I put the breakpoint after the code, it crashes. So it does seem to be this code.
In any case, what am I doing wrong or how could I debug it?
- (void) recordAndRecognizeWithLang:(NSString *) lang
{
NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:lang];
self.sfSpeechRecognizer = [[SFSpeechRecognizer alloc] initWithLocale:locale];
if (!self.sfSpeechRecognizer) {
[self sendErrorWithMessage:#"The language is not supported" andCode:7];
} else {
// Cancel the previous task if it's running.
if ( self.recognitionTask ) {
[self.recognitionTask cancel];
self.recognitionTask = nil;
}
//[self initAudioSession];
self.recognitionRequest = [[SFSpeechAudioBufferRecognitionRequest alloc] init];
self.recognitionRequest.shouldReportPartialResults = [[self.command argumentAtIndex:1] boolValue];
// https://developer.apple.com/documentation/speech/sfspeechrecognizerdelegate
// only callback is availabilityDidChange
self.sfSpeechRecognizer.delegate = self;
self.recognitionTask = [self.sfSpeechRecognizer recognitionTaskWithRequest:self.recognitionRequest resultHandler:^(SFSpeechRecognitionResult *result, NSError *error) {
NSLog(#"recognise");
if (error) {
NSLog(#"error %ld", error.code);
// code 1 or 203 or 216 = we called abort via self.recognitionTask cancel
// 1101 is thrown when in simulator
// 1700 is when not given permission
if (error.code==203){ //|| error.code==216
// nothing, carry on, this is bullshit, or maybe not...
[self sendErrorWithMessage:#"sfSpeechRecognizer Error" andCode:error.code];
}else{
[self stopAndRelease];
// note: we can't send error back to js as I found it crashes (when recognising, then switch apps, then come back)
[self sendErrorWithMessage:#"sfSpeechRecognizer Error" andCode:error.code];
return;
}
}
if (result) {
NSMutableArray * alternatives = [[NSMutableArray alloc] init];
int maxAlternatives = [[self.command argumentAtIndex:2] intValue];
for ( SFTranscription *transcription in result.transcriptions ) {
if (alternatives.count < maxAlternatives) {
float confMed = 0;
for ( SFTranscriptionSegment *transcriptionSegment in transcription.segments ) {
//NSLog(#"transcriptionSegment.confidence %f", transcriptionSegment.confidence);
if (transcriptionSegment.confidence){
confMed +=transcriptionSegment.confidence;
}
}
NSLog(#"transcriptionSegment.transcript %#", transcription.formattedString);
NSMutableDictionary * resultDict = [[NSMutableDictionary alloc]init];
[resultDict setValue:transcription.formattedString forKey:#"transcript"];
[resultDict setValue:[NSNumber numberWithBool:result.isFinal] forKey:#"final"];
float conf = 0;
if (confMed && transcription.segments && transcription.segments.count && transcription.segments.count>0){
conf = confMed/transcription.segments.count;
}
[resultDict setValue:[NSNumber numberWithFloat:conf]forKey:#"confidence"];
[alternatives addObject:resultDict];
}
}
[self sendResults:#[alternatives]];
if ( result.isFinal ) {
//NSLog(#"recog: isFinal");
[self stopAndRelease];
}
}
}];
//[self.audioEngine.inputNode disconnectNodeInput:0];
AVAudioFormat *recordingFormat = [self.audioEngine.inputNode outputFormatForBus:0];
//AVAudioFormat *recordingFormat = [[AVAudioFormat alloc] initStandardFormatWithSampleRate:44100 channels:1];
NSLog(#"samplerate=%f", recordingFormat.sampleRate);
NSLog(#"channelCount=%i", recordingFormat.channelCount);
// tried this but does not prevent crashing
//if (recordingFormat.sampleRate <= 0) {
// [self.audioEngine.inputNode reset];
// recordingFormat = [[self.audioEngine inputNode] outputFormatForBus:0];
//}
sleep(1); // to prevent random crashes
#try {
[self.audioEngine.inputNode removeTapOnBus:0];
} #catch (NSException *exception) {
NSLog(#"removeTapOnBus exception");
}
sleep(1); // to prevent random crashes
#try {
NSLog(#"install tap on bus");
[self.audioEngine.inputNode installTapOnBus:0 bufferSize:1024 format:recordingFormat block:^(AVAudioPCMBuffer * _Nonnull buffer, AVAudioTime * _Nonnull when) {
//NSLog(#"tap");
[self.recognitionRequest appendAudioPCMBuffer:buffer];
}];
} #catch (NSException *exception) {
NSLog(#"installTapOnBus exception");
}
sleep(1); // to prevent random crashes
[self.audioEngine prepare];
NSError* error = nil;
BOOL isOK = [self.audioEngine startAndReturnError:&error];
if (!isOK){
NSLog(#"audioEngine startAndReturnError returned false");
}
if (error){
NSLog(#"audioEngine startAndReturnError error");
}
}
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;
I am developing an app in which I have to track crashes. There is a restriction that I can't use any third party source like Twitter's Fabric framework to handle crash logging.
Currently I am only able to get the reason for crash. I am not able to get the exact point of crash.
What I am doing:
In my app delegate's didFinishLaunchingWithOptions method I had made my own exception handler:
NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);
uncaughtExceptionHandler ----
void uncaughtExceptionHandler(NSException *exception) {
NSLog(#"CRASH: %#", exception);
NSLog(#"callStackSymbols: %#", [exception callStackSymbols]);
NSLog(#"callStackReturnAddresses: %#", [exception callStackReturnAddresses]);
NSLog(#"reason: %#", [exception reason]);
NSLog(#"name: %#", [exception name]);
NSLog(#"%s %d %s %s", __FILE__, __LINE__, __PRETTY_FUNCTION__, __FUNCTION__);
// Internal error reporting
}
I crashed my app in viewDidLoad method using this:
NSArray *myary;
myary = [NSArray arrayWithObjects:#"sad", nil];
NSString *str = [myary objectAtIndex:22];
Here is my Stack Trace.
Is their any way to achieve what I want?
I tried following these solutions from SO but they don't give me any lead:
Solution 1
Solution 2
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 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