2010-11-23 7 views
0

Obj-C MyStreamHandler.mmクラスファイルにlibxmlエラーハンドラを作成して割り当てました。ストリームパーサはxmlTextReaderSetErrorHandlerを使用します。エラーハンドラでは、[NSException raise:format:]を使用してObj-C例外を発生させています。しかし、例外は私のObj-Cクラスの中でそれが@try/@catchブロックに捕らえられていません。Obj-Cのエラーハンドラコールバック関数(Obj-C++)がObj-Cで捕捉されない

無効なxmlが検出された場合(この場合、</foo </bar>)、libxml内でコールバックが発生します。エラーハンドラはそれほど確実であると呼ばれており、NSExceptionも呼び出されています。しかし、例外はlibxmlのクライアントであるObj-Cクラスでは捕捉されていません。

MyStreamHandler.mm

#import <libxml/xmlreader.h> 

#import "MyStreamHandler.h" 

void MyErrorCallback(void *arg, const char *msg, xmlParserSeverities severity, xmlTextReaderLocatorPtr locator); 

@implementation MyStreamHandler 

-(void)readStream:(xmlTextReaderPtr)streamAPI 
{ 
    xmlTextReaderSetErrorHandler(streamAPI, (xmlTextReaderErrorFunc)MyErrorCallback, NULL); 

    @try 
    { 
     while (xmlTextReaderRead(streamAPI) == 1) 
     { 
      // Loop through the XML until the malformed XML is hit. 
     } 
    } 
    @catch (id e) 
    { 
     NSLog(e); 
    } 
} 

@end 

void MyErrorCallback(void *arg, const char *msg, xmlParserSeverities severity, xmlTextReaderLocatorPtr locator) 
{ 
    [NSException raise:@"MyException" format:@"Something bad happened: %s",msg]; 
}

は、ここでは、このコールバックと例外をトリガーするサンプルXMLファイルです:

​​

ここでは、以下のキャッチされない例外によって引き起こされる関連するコールスタックです:

*** Terminating app due to uncaught exception 'MyException', reason: 'Something bad happened: Opening and ending tag mismatch: content line 0 and container 
' 

*** Call stack at first throw: 
(_NSCallStackArray*)0x10301a40; count=33 { 
0 CoreFoundation      0x04324be9 __exceptionPreprocess + 185 
1 libobjc.A.dylib      0x044795c2 objc_exception_throw + 47 
2 CoreFoundation      0x042dd628 +[NSException raise:format:arguments:] + 136 
3 CoreFoundation      0x042dd59a +[NSException raise:format:] + 58 
4 MyApp        0x00ee1b85 _Z25MyErrorCallbackPvPKc19xmlParserSeveritiesS_ + 319 
5 libxml2.2.dylib      0x0401766c xmlTextReaderStandalone + 105 
6 libxml2.2.dylib      0x04018793 xmlTextReaderSetErrorHandler + 838 
7 libxml2.2.dylib      0x03f69c78 __xmlRaiseError + 1222 
8 libxml2.2.dylib      0x03f6d564 namePush + 1283 
9 libxml2.2.dylib      0x03f75e2c xmlParseXMLDecl + 1291 
10 libxml2.2.dylib      0x03f80b6d xmlParseChunk + 3984 
11 libxml2.2.dylib      0x0401a255 xmlTextReaderGetAttribute + 816 
12 libxml2.2.dylib      0x0401bb34 xmlTextReaderRead + 441 
13 MyApp        0x00ec2919 +[MyStreamHandler readStream:] 
... 
Application call stack 
... 
24 CoreFoundation      0x0429567d __invoking___ + 29 
25 CoreFoundation      0x04295551 -[NSInvocation invoke] + 145 
26 Foundation       0x027bd555 -[NSInvocationOperation main] + 51 
27 Foundation       0x0272bbd2 -[__NSOperationInternal start] + 747 
28 Foundation       0x0272b826 ____startOperations_block_invoke_2 + 106 
29 libSystem.B.dylib     0x925a0024 _dispatch_call_block_and_release + 16 
30 libSystem.B.dylib     0x925922f2 _dispatch_worker_thread2 + 228 
31 libSystem.B.dylib     0x92591d81 _pthread_wqthread + 390 
32 libSystem.B.dylib     0x92591bc6 start_wqthread + 30 
} 
terminate called after throwing an instance of 'NSException' 

これは完全に偽ですか?私はObj-C++関数内からObj-C例外をスローし、Obj-Cコードの通常の@ try/@ catchブロックで処理できますか?または、Obj-C++ try/catchブロックを使用して実際のObj-C++例外を発生させる必要がありますか?

ご協力いただければ幸いです。

答えて

1

ココアとココアタッチの例外は、プログラマエラーのためにのみ予約されています。エンドユーザーに出荷された時点でそれらをプロダクションコードで使用することを期待するべきではありません。

また、すべての中間スタックフレームを制御する場合にのみ、API境界にスローされた例外をキャッチすることは通常想定できません。したがって、あなたが与えた例では、Objective-C例外の知識を持たないコードから例外を投げているので、有効な状態に残すことはできません。

エラーハンドラにエラー情報を他の方法で上位レベルのコードに渡す必要があります。通常、コールバックとコールバック登録APIにはvoid *という引数があります(最終的な引数はxmlTextReaderSetErrorHandlerなど、ハンドラ関数の最初の引数になります)。コールバックにコンテキストを関連付けることができます。複数の可能性のあるドキュメントのうち、読んでいるものがエラーを引き起こしています。

+0

私たちのパターンは、ファイルリーダーで例外を使用し、アプリケーションに制御を渡す前にそれらをキャッチすることです。次にそれらをNSError **に変換し、それ以降はそれを使用します。 ガイダンスのおかげでクリス。 – xmlhack

+0

Javaまたは.NETのプラットフォームから慣れていないかどうかにかかわらず、そのパターンを使用すべきではありません。 Objective-CやC++で例外を任意のCコードから投げ捨てることはできません。 Cコードで使用されている状態が矛盾している可能性があり、クラッシュ、ハング、セキュリティエクスプロイトなどにつながる可能性があります。 –

+0

これは任意のCコードではなく、状態に矛盾がありません。これは、Javaまたは.NETプラットフォームでの使用でもありません。これは、ほぼ10年間出荷されているObjective-CおよびObj-C++コードです。我々はまた、必要な毛羽立ち検査を既に行っている。 – xmlhack

0

例外のパラダイムは、余分なNSError**パラメータを使って捨てる必要がないので、例外的なパラダイムが一般的により洗練されたコードにつながると思うので、例外に関するアップルのアドバイスのファンではありません。エラーを示す値を返します。

Objective-C例外は、期待していないコードにも伝播することは絶対に許されません。これはObjective-C例外を処理するためにかなりのコードが書かれていないためです。例えば、libxml2は、スタックの巻き戻しが正常に行われず、リークやその他の不快感を招くことはほとんどありません。

あなたの例外がハンドラによってキャッチされなかった理由はわかりません(多分@throwにする必要があります)が、それは無関係です。このような状況では使用できません。

あなたのコールバックで行うべきことは、あなたがエラーを抱えていることに気づくだけで、それを記録または記録してから正常に戻ることがあります。エラーが致命的である場合、libxml2はあなたを助けないで終了する方法を知っています。

+0

長所と短所は、ストリーム操作でlibxml2から-1応答値をキャッチし、エラーを処理する代わりに、遅く制御されたスタックをスタックから外して解決することです。これは明らかに動作していない例外をスローするはるかに単純なメソッドの代わりに、そうでない場合はお勧めできないようです。 – xmlhack

関連する問題