10

オープン ソース プロジェクトに取り組んでいるときに、次の C 関数の宣言と実装に出くわしました。

// FSNData.h
NSString *stringForMimeType(MimeType type);

@interface FSNData : NSObject
// All the expected objective-c property and instance method declarations
@end

// FSNData.m
#import "FSNData.h"

// where 'type' is an enum
// this does work as expected
NSString *stringForMimeType(MimeType type) {
    switch (type) {
        case MimeType_image_jpeg: return @"image/jpeg";
        case MimeType_image_png:  return @"image/png";
        default:
            NSLog(@"ERROR: FSNData: unknown MimeType: %d", type);

        // do not return "application/octet-stream"; instead, let the recipient guess
        // http://en.wikipedia.org/wiki/Internet_media_type
        return nil;
    }
}

@implementation

// all properties and methods defined in FSData.h implemented as expected

@end

この例は、問題なくクラス レベルのメソッドとして簡単に書き直すことができます。そのままでは、stringFormMimeType()sillを使用するにはFSNDataヘッダー ファイルをインポートする必要があります。

Apple docsを見ると、次のようにのみ記載されています。

Objective-C は ANSI C を基盤としているため、ストレート C コードと Objective-C コードを自由に混在させることができます。さらに、/usr/include の BSD ライブラリ インターフェイスなど、非 Cocoa プログラム インターフェイスで定義された関数をコードから呼び出すことができます。

C 関数がどのような場合に Objective-C メソッドを優先するかについては言及されていません。

この時点でわかる唯一の利点は、クラス メソッドとは対照的に、上記の関数を呼び出すと、一部の Objective-C ランタイム呼び出しがスキップされることです。の典型的な使用例ではFSNData、これによってユーザー (おそらく開発者) のパフォーマンスが大幅に向上することはありません*。

クラス メソッドよりも C 関数を優先することには、(コーディング スタイル以外に) どのような利点がありますか?

*FSNDataFSNetworkingライブラリの一部として使用されるため、アプリケーションのライフ サイクル中に何千ものネットワーク操作が実行されるとは思えません。

4

2 に答える 2

12

つまり、C (または C++) の実装は非常に便利です。

  • 抽象化のために
  • 再利用のために
  • 中・大規模プログラムを作成する場合
  • パフォーマンス クリティカル パス内
  • 「インテリア」実装の場合

クラス メソッドよりも C 関数を優先することには、(コーディング スタイル以外に) どのような利点がありますか?

  • ObjC メッセージングは​​、間接的な関数呼び出しを導入します。これらはオプティマイザ用のファイアウォールです。
  • C 関数はアクセスを簡単に制限できますが、「プライベート」な ObjC 実装は ObjC ランタイムを使用して検索されたり、誤ってオーバーライドされたりする可能性があります。
  • C 関数は、参照されていない場合、実行可能ファイルから削除されるか、プライベートにされる場合があります。再利用可能なコードを書く場合 (そうするべきです)、これはバイナリ サイズと読み込み時間に大きな影響を与える可能性があります。参照/使用されていない C 関数は削除される可能性がありますが、ObjC の型とメソッドは保持されます (それらのすべてを含む)。参照)。これが、ObjC 静的ライブラリのごく一部のみを使用すると、アプリのバイナリ サイズが大幅に大きくなる可能性がある理由です。ライブラリ内のすべての objc クラスが保持されます。そのライブラリが C または C++ の場合は、参照されるものだけが必要なため、非常にわずかな増加で済みます。何が参照され、何が参照されていないかは、C および C++ で証明する方が簡単です。
  • C 関数は、コンパイル中またはリンク時の最適化フェーズ中にインライン化できます。
  • コンパイラとオプティマイザは、C 関数を使用して多くの最適化を行うことができますが (手続き間の最適化など)、ObjC メソッドは常に間接的であるためほとんど実行できません。
  • ObjC メッセージディスパッチのオーバーヘッドを回避するには (前述のとおり)
  • ObjC オブジェクトと対話するときに、追加の参照カウント操作と自動解放プール アクティビティが発生する可能性があります。

もちろん、必要のないものや使用しないものにお金を払っても常に損をするわけではありません。また、ObjC クラス メソッドには C 関数よりも優れた利点があることも覚えておいてください。したがって、ツールボックスの別のツールとして C または C++ の実装を検討してください。複雑さとプロジェクトのサイズが大きくなるにつれて、それらは非常に便利であり、プログラムをより高速にするために使用できます。2015年に後悔する可能性が最も低いことをしてください;)

于 2013-09-22T22:55:26.803 に答える
10

objc_msgSend呼び出しを回避することによるわずかなパフォーマンスの違いについては既に触れました。Objective-C クラスのメソッドもサブクラスでオーバーライドされるため、C でメソッドを実装すると、サブクラスでオーバーライドされなくなります。関連して、そのランタイム継承/ポリモーフィズムのために、Objective-C メソッドは決してインライン化できませんが、C 関数はパフォーマンス向上のためにコンパイラによってインライン化される可能性があります。

を回避することになるとobjc_msgSend、賢い人がかつて私にこう言いましobjc_msgSendた。

于 2013-09-22T21:36:42.427 に答える