呼び出しobjc_msgSend法による64ビットでのクラッシュ解決法

2635 ワード

これまで64ビット以外のマシンですべての正常なプログラムをテストしていたが、iPhone 5 sで理由もなく崩壊した.クラッシュの場所はobjc_を呼び出すことですmsgSendで表示されます.苦労して検索した結果、アップルの公式サイトにはこのような記述があることが分かった.
Dispatch Objective-C Messages Using the Method Function’s Prototype
An exception to the casting rule described above is when you are calling the  objc_msgSend  function or any other similar functions in the Objective-C runtime that send messages. Although the prototype for the message functions has a variadic form, the method function that is called by the Objective-C runtime does not share the same prototype. The Objective-C runtime directly dispatches to the function that implements the method, so the calling conventions are mismatched, as described previously. Therefore you must cast the  objc_msgSend  function to a prototype that matches the method function being called.
Listing 2-14 shows the proper form for dispatching a message to an object using the low-level message functions. In this example, the doSomething:  method takes a single parameter and does not have a variadic form. It casts the  objc_msgSend  function using the prototype of the method function. Note that a method function always takes an  id  variable and a selector as its first two parameters. After the  objc_msgSend function is cast to a function pointer, the call is dispatched through that same function pointer.
Listing 2-14  Using a cast to call the Objective-C message sending functions
- (int) doSomething:(int) x { ... }
- (void) doSomethingElse {
   int (*action)(id, SEL, int) = (int (*)(id, SEL, int)) objc_msgSend;
   action(self, @selector(doSomething:), 0);
}

objcを直接使うことはできないということらしいです.msgSendのプロトタイプメソッドは匿名で呼び出されます.そうしないと異常が発生します.結局上記の方法を強制的に一定の方法に変換してみたところ、再運転はクラッシュせず、Luck!!
原文:https://developer.apple.com/library/ios/documentation/General/Conceptual/CocoaTouch64BitGuide/ConvertingYourAppto64-Bit/ConvertingYourAppto64-Bit.html
補足説明(2015-8-5):
構造体を返す方法についてobjc_を使用するとmsgSendが呼び出すと異常EXCが放出されますBAD_ACCESS:
CGSize (*action)(id, SEL, int) = (CGSize (*)(id, SEL, int)) objc_msgSend;
CGSize size = action(self, @selector(doSomething:), 0);

このようなやり方では、クラッシュの問題が発生する可能性があります(ただし、プログラムごとに必ず発生するとは限りません)、公式ドキュメントを見てみると、objc_msgSendには拡張バージョンobjc_がありますmsgSend_stretは、戻り構造体の処理に特化しているため、コードを以下のように変更すれば問題を解決できます.
CGSize (*action)(id, SEL, int) = (CGSize (*)(id, SEL, int)) objc_msgSend_stret;
CGSize size = action(self, @selector(doSomething:), 0);

注意:この調整はarmv 7アーキテクチャでのみ必要であり、arm 64が含まれている場合は必要ありません.