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


90

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

iOS Prefix.pchファイルに何を追加することをお勧めしますか(またはお勧めしませんか)?Prefix.pchはどのように見えますか?


件名に関する詳細なブログ投稿:cimgf.com/2010/05/02/my-current-prefix-pch-file
hpique

2
たとえばMacros.h、マクロをヘッダーファイルに挿入し、このファイルをにインポートしますprefix.pch
Malloc、2013

私も同じ問題に直面しています... Xcode 6.1で解決する方法
Yalamandarao 2015

回答:


121

Ewww….pchファイルにマクロを入れないでください!.pchファイルは、定義上、プロジェクト固有のプリコンパイル済みヘッダーです。プロジェクトのコンテキストを超えて使用することはできません。#includeまた、sと以外は何も含めないでください#import

あなたはいくつかのマクロを持っていると、そのようなあなたは、その後、独自のヘッダファイルに」日を貼り、ヘッダ間共有したいという場合は- Common.hと-または何#include という .PCHの初めに。


Common.hには何を含めますか?
hpique

4
何も; さまざまな#defineなどを入れます。
bbum

37

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

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

モジュールを使用すると、PCHは必要ありません。おそらく@import、依存関係に対してローカルを使用することを優先して、モジュールを完全に削除する必要があります。その場合、PCHはローカルの依存関係のインクルージョンを入力する手間を省くだけです(とにかくIMOを実行する必要があります)。

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

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


参考文献


ノート

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

モジュール対応プロジェクトの完全な再構築とはどういう意味ですか。この新しい-Swift.hブリッジヘッダーは、.pchの正しい候補ではありません。しかし、私は人々がそれをするのを見ました。誰かがそうするかどうかを見ることができるように。.pchには常に変更されるヘッダーがあります。したがって、-Swift.hが再生成されるたびに、.pchファイル内のすべてが再構築されます。これに同意しますか?もっと入力がありますか?
MadNik

@MadNikアプリのPCHに、開発中のライブラリ/フレームワークのマスターヘッダーが含まれているとします。次に例を示します#import "MyLib/MyLib.h"MyLib.h変更によってファイルが含まれる場合は常に、アプリ内のすべてのソースファイルを再コンパイルする必要があります。MyLibを1つのソースファイルで使用する場合、MyLibが変更されたときにそのファイルのみを再コンパイルする必要があります。信じられないかもしれませんが、最近はPCHファイルを使用していません。
ジャスティン

8

私はbbumに同意します。PCHファイルに対する私の見方は、ほとんどの#includeor #importステートメントのみを含む必要があるということです。したがって、役立つ高レベルのマクロがたくさんある場合は、bbumが示唆しているようにCommon.h、それらをそのような#importファイルで定義します。

私は通常、さらに一歩進み、にPCHファイルを使用する#importと呼ばれるファイルXXCategories.h(ここでXX含まれている使用するクラスの命名接頭辞規則である)#importすべての私のUIKitとFoundationのクラス分類のための秒:NSString+XXAdditions.hUIColor+XXAdditons.hなど


気になるだけです。.PCHファイルで、さまざまなCommon.hを#importインポートする#importこととそれらを直接インポートすることの違いは何ですか?それらは同じではないでしょうか?それともパフォーマンスに影響しますか?
Hlung 2012

私の知る限り、本当の違いはありません。もっとベストプラクティスだと思います。一連のマクロやその他のものをPCHファイルに押し込むのではなく、#importおよびのみに対応する必要があり#includeます。
CIFilter 2012

1
違いは再利用性です。PCHはプロジェクト固有です。Common.hは多くのプロジェクトに共通です。再利用できるサブプロジェクトを作成するのではなく、すべてのutilクラスをプロジェクトに入れない理由を尋ねるのと同じです。単純なコピーペーストだけなので、不自然な例ですが...コピーペーストはいたずらです。
bandejapaisa 2013年

6

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

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

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

パフォーマンスが心配な場合は、心配しないでください。アップルの発言をご覧ください。

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

マスターヘッダーファイルを含めるとプログラムが肥大化するのではないかと心配している場合でも、心配しないでください。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];

2
ここで別の便利な方法:#define async(...) dispatch_async(dispatch_get_main_queue(), __VA_ARGS__ )...メインスレッドでブロックを実行するには:async(^{ self.someLabel.text = @":D"; });
AlejandroIván'30
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.