web-dev-qa-db-ja.com

iOS Prefix.pchのベストプラクティス

IOSプロジェクトのPrefix.pchにさまざまな便利なマクロを追加する多くの開発者を見てきました。

IOS Prefix.pchファイルに追加することを推奨する(または推奨しない)ことは何ですか? Prefix.pchはどのように見えますか?

88
hpique

Ewww ... .pchファイルにマクロを入れないでください! .pchファイルは、定義により、プロジェクト固有のプリコンパイル済みヘッダーです。プロジェクトのコンテキストを超えて使用するべきではありません。また、#include#imports。

いくつかのマクロがあり、ヘッダー間で共有したい場合は、独自のヘッダーファイルにそれらを貼り付けます— Common.hまたはその他—および#includethat .pchの先頭。

122
bbum

最新のiOSおよびOS Xの場合、人々はModulesを使用する必要があります。これは新しいプロジェクトに対してデフォルトで有効になっており、インポート/包含は@import

モジュールを使用すると、コンパイラはモジュールのコンテンツ(フレームワークのヘッダーなど)の中間表現を作成できます。 PCHと同様に、この中間表現は複数の翻訳で共有できます。ただし、モジュールは必ずしもターゲット固有ではなく、その宣言をローカライズする必要がないため(*.pch)。この表現は、冗長なコンパイラー作業を節約できます。

モジュールを使用する場合、PCHは必要ありません。おそらく、@import依存関係に対してローカル。その場合、PCHはtyping依存関係のローカルなインクルード(とにかくIMOを行うべきです)からあなたを救うだけです。

さて、元の質問を振り返ると、PCHをあらゆる種類のランダムなもので満たすことは避けてください。マクロ、定数、#defines、およびあらゆる種類の小さなライブラリ。一般的に、ソースファイルの大部分にとって本当に不要なものは省略する必要があります。 PCHにあらゆる種類のものを置くことは、単に重みと依存関係を追加することです。私は人々がリンクするものすべてをPCHに入れているのを見ます。実際には、補助フレームワークは通常、ほとんどの場合、少数の翻訳に対してのみ表示される必要があります。例えば。 「ここにStoreKitのものがあります-StoreKitをインポートするのは、それがmust表示される場合のみです。具体的には、これら3つの翻訳」これにより、ビルド時間が短縮され、依存関係を追跡できるため、コードをより簡単に再利用できます。したがって、ObjCプロジェクトでは、通常Foundationに立ち寄ることになります。 UIが多数ある場合は、PCHにUIKitまたはAppKitを追加することを検討してください。これはすべて、ビルド時間を最適化することを前提としています。 (ほぼ)すべてを含む大規模なPCHの問題の1つは、不要な依存関係の削除に非常に時間がかかることです。プロジェクトの依存関係が大きくなり、ビルド時間が長くなると、ビルド時間を短縮するために、不要な依存関係を排除して反撃する必要があります。また、頻繁に変更されるものはすべて、一般にPCHに保管しないでください。変更には完全な再構築が必要です。 PCHを共有するオプションがいくつかあります。 PCHを使用する場合は、共有のサポートを目指してください。

私がPCHに入れたものに関しては、数年前にターゲットの大部分でそれらの使用をやめました。そこには通常、資格を得るのに十分な共通点がありません。 C++、ObjC、ObjC++、およびCを記述していることに注意してください。コンパイラは、ターゲットの各言語ごとに1つを出力します。したがって、それらを有効にすると、コンパイル時間が遅くなり、I/Oが高くなります。最終的に、依存関係を増やすことは、複雑なプロジェクトで依存関係と戦うための良い方法ではありません。複数の言語/方言を使用する場合、特定のターゲットに必要な依存関係には多くのバリエーションがあります。いいえ、すべてのプロジェクトに最適であるとはお勧めしませんが、それは大規模プロジェクトの依存関係管理にある程度の視点を与えます。


参照資料


ノート

  • この質問はもともと、モジュールの導入の数年前に尋ねられました。
  • 現在(Xcode 5.0)、モジュールはCおよびObjCで機能しますが、C++では機能しません。
36
justin

私はbbumに同意します。 PCHファイルに関する私の見解は、#includeまたは#importステートメント。したがって、有用な高レベルマクロがたくさんある場合は、Common.hおよび#import bbumが示唆するとおり、そのファイル。

私は通常、さらに一歩進んで、PCHファイルを使用して#importというファイルXXCategories.h(ここで、XXは、使用するクラスの命名プレフィックス規則です)#importsすべての私のUIKitおよびFoundationクラスのカテゴリ:NSString+XXAdditions.hUIColor+XXAdditons.hなど.

8
CIFilter

ヘッダーファイル「macros.h」を作成します

このヘッダーをPrefix.pchにインポートします

このmacros.hには、すべてのフレームワークと他の重要なものを入れます。

パフォーマンスが心配な場合は、心配しないで、Appleのコメント:

ヘッダーとパフォーマンス

マスターヘッダーファイルを含めるとプログラムが肥大化する可能性があることを心配していても心配しないでください。 OS Xインターフェースはフレームワークを使用して実装されているため、これらのインターフェースのコードは実行可能ファイルではなく、動的共有ライブラリに存在します。さらに、プログラムで使用されるコードのみが実行時にメモリにロードされるため、メモリ内のフットプリントも同様に小さくなります。コンパイル中に多数のヘッダーファイルを含めることについては、もう一度心配しないでください。 Xcodeは、コンパイル時間を短縮するプリコンパイル済みヘッダー機能を提供します。すべてのフレームワークヘッダーを一度にコンパイルすることにより、新しいフレームワークを追加しない限り、ヘッダーを再コンパイルする必要はありません。それまでの間、含まれているフレームワークの任意のインターフェイスを使用して、パフォーマンスをほとんどまたはまったく低下させることはできません。

また、私のmacros.hには、次のような多くの定数を入れています。

// delegate
#define UIAppDelegate (AppDelegate *)[[UIApplication sharedApplication] delegate]
#define APPDELEGATE   ((AppDelegate *)[[UIApplication sharedApplication] delegate])

// system
#define IS_IPHONE_4INCH (UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPhone && [UIScreen mainScreen].bounds.size.height==568)
#define IS_IPAD                     (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)

// screen size
#define IS_IPAD (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
#define IS_IPHONE (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
#define IS_IPHONE_4 (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 480.0)
#define IS_IPHONE_5 (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 568.0)
#define IS_IPHONE_6 (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 667.0)
#define IS_IPHONE_6PLUS (IS_IPHONE && [[UIScreen mainScreen] nativeScale] == 3.0f)
#define IS_IPHONE_6_PLUS (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 736.0)
#define IS_RETINA ([[UIScreen mainScreen] scale] == 2.0)
#define IS_RETINA_DISPLAY ([[UIScreen mainScreen] respondsToSelector:@selector(displayLinkWithTarget:selector:)] && ([UIScreen mainScreen].scale == 2.0))
#define IS_PORTRAIT                 UIInterfaceOrientationIsPortrait([[UIApplication sharedApplication] statusBarOrientation])
#define IS_LANDSCAPE                UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation])

//system version
#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
#define SYSTEM_VERSION_GREATER_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending)

// math
#define DEGREES_TO_RADIANS(angle) ((angle) / 180.0 * M_PI)
#define RADIANS_TO_DEGREES(radians) ((radians) * (180.0 / M_PI))

// cores
#define RGB(r,g,b)    [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1]
#define RGBA(r,g,b,a) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:a]
#define MAKECOLOR(R, G, B, A) [UIColor colorWithRed:((float)R/255.0f) green:((float)G/255.0f) blue:((float)B/255.0f) alpha:A]
#define MAKECOLORFROMHEX(hexValue) [UIColor colorWithRed: ((float)((hexValue & 0xFF0000) >> 16))/255.0 green:((float)((hexValue & 0xFF00) >> 8))/255.0 blue:((float)(hexValue & 0xFF))/255.0 alpha:1.0]



//customizations
#define SHOW_STATUS_BAR               [[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationNone];
#define HIDE_STATUS_BAR               [[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationNone];

#define SHOW_NAVIGATION_BAR           [self.navigationController setNavigationBarHidden:FALSE];
#define HIDE_NAVIGATION_BAR           [self.navigationController setNavigationBarHidden:TRUE];

#define VC_OBJ(x) [[x alloc] init]
#define VC_OBJ_WITH_NIB(x) [[x alloc] initWithNibName : (NSString *)CFSTR(#x) bundle : nil]

#define RESIGN_KEYBOARD [[[UIApplication sharedApplication] keyWindow] endEditing:YES];

#define CLEAR_NOTIFICATION_BADGE                       [UIApplication sharedApplication].applicationIconBadgeNumber = 0;
#define REGISTER_APPLICATION_FOR_NOTIFICATION_SERVICE  [[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)]

#define HIDE_NETWORK_ACTIVITY_INDICATOR                 [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
#define SHOW_NETWORK_ACTIVITY_INDICATOR                 [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
6
Leo Cavalcante