iOS Prefix.pch 最佳实践

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2845211/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 17:15:10  来源:igfitidea点击:

iOS Prefix.pch best practices

iosobjective-cxcodepch

提问by hpique

I have seen many developers that add various convenience macros to the Prefix.pch of their iOS projects.

我见过很多开发人员在他们的 iOS 项目的 Prefix.pch 中添加了各种方便的宏。

What do (or don't) you recommend adding to the iOS Prefix.pch file? What does your Prefix.pch look like?

您建议(或不)将什么添加到 iOS Prefix.pch 文件中?你的 Prefix.pch 是什么样的?

回答by bbum

Ewww… don't put macros in a .pch file! A .pch file is, by definition, a project specific precompiled header. It really shouldn't be used beyond the context of the project and it really shouldn't contain anything but #includes and #imports.

Ewww...不要将宏放在 .pch 文件中!根据定义,.pch 文件是项目特定的预编译头文件。它真的不应该在项目的上下文之外使用,它真的不应该包含除了#includes 和#imports 之外的任何东西。

If you have some macros and such that you want to share between headers, then stick 'em in a header file of their own — Common.hor whatever — and #includethatat the beginning of the .pch.

如果你有一些宏等,你想报头之间的共享,然后在自己的头文件把脚伸-Common.h或者别的什么-并且#include在.PCH的开始。

回答by justin

For modern iOS and OS X, people should be using Modules. This is enabled by default for new projects, and importing/inclusion is accomplished using @import.

对于现代 iOS 和 OS X,人们应该使用Modules。默认情况下为新项目启用此功能,导入/包含使用@import.

Modules allow the compiler to create an intermediate representation of the contents of a module (e.g. a framework's headers). Much like a PCH, this intermediate representation may be shared across multiple translations. But modules take this one step further because a module is not necessarily target specific, and their declarations need not be localized (to a *.pch). This representation can save you a ton redundant compiler work.

模块允许编译器创建模块内容的中间表示(例如框架的头文件)。很像 PCH,这个中间表示可以在多个翻译之间共享。但是模块更进一步,因为模块不一定是特定于目标的,并且它们的声明不需要本地化(到 a *.pch)。这种表示可以为您节省大量冗余的编译器工作。

Using modules, you do not need a PCH, and you probably should just do away with them entirely -- in favor of using @importlocal to the dependency. In that case, a PCH is only saving you from typinginclusions local to dependencies (which IMO you should be doing anyway).

使用模块,你不需要 PCH,你可能应该完全取消它们——支持使用@import本地依赖。在这种情况下,PCH 只会使您免于键入依赖项的本地包含(IMO 无论如何您都应该这样做)。

Now, if we look back to the original question: You should avoid filling your PCH with all sorts of random things; Macros, constants, #defines, and all sorts of little libraries. Generally, you should omit what really is unnecessary to the majority of your source files. Putting all sorts of stuff in your PCH is just adding a bunch of weight and dependency. I see people put everything they link and more to in the PCH. In reality, auxiliary frameworks typically only need to be visible to a few translations in most cases. E.g. "Here is our StoreKit stuff - let's import StoreKit only where it mustbe visible. Specifically, these 3 translations". This keeps your build times down, and helps you keep track of your dependencies, so that you may reuse code more easily. So in an ObjC project, you would usually stop at Foundation. If there is a lot of UI, then you might consider adding UIKit or AppKit to your PCH. This is all assuming you want to optimize build times. One of the problems with large PCHs that include (nearly) everything is that removing unnecessary dependencies is very time consuming. Once your project's dependencies grow and your build times go up, you need to fight back by eliminating unnecessary dependencies in order to reduce your build times. Also, anything that changes often should generally be kept out of your PCH. A change requires a full rebuild. There are some options to share PCHs. If you use PCHs, do aim to support sharing.

现在,如果我们回顾一下最初的问题:你应该避免用各种随机的东西填充你的 PCH;宏、常量#defines和各种小库。一般来说,你应该忽略真正不需要您的大部分源文件。把各种各样的东西放在你的 PCH 中只是增加了一堆重量和依赖性。我看到人们将他们链接的所有内容以及更多内容都放在 PCH 中。实际上,在大多数情况下,辅助框架通常只需要对少数翻译可见。例如“这是我们的 StoreKit 东西 - 让我们只在必须的地方导入 StoreKit可见。具体来说,这 3 个翻译”。这可以缩短构建时间,并帮助您跟踪依赖项,以便您可以更轻松地重用代码。因此,在 ObjC 项目中,您通常会停在 Foundation。如果有很多的 UI,那么您可能会考虑将 UIKit 或 AppKit 添加到您的 PCH。这都是假设您想要优化构建时间。包含(几乎)所有内容的大型 PCH 的问题之一是删除不必要的依赖项非常耗时。一次您的项目的依赖项会增加并且构建时间会增加,您需要通过消除不必要的依赖项来进行反击以减少构建时间。此外,任何经常更改的内容通常都应该放在您的 PCH 之外。更改需要完全重建。有一些共享 PCH 的选项。如果您使用 PCH,

As far as what I put in my PCH: I stopped using them for the vast majority of targets years ago. There just usually is not enough in common to qualify. Bear in mind, I write C++, ObjC, ObjC++ and C - the compiler emits one for each lang in your target. So enabling them often resulted in slower compile times and higher I/O. Ultimately, increasing dependency is not a good way to fight dependency in complex projects. Working with multiple languages/dialects, there are is much variation in the dependencies required for a given target. No, I would not advise that as optimal for every project, but that does give some perspective to dependency management in larger projects.

至于我在 PCH 中的内容:几年前我停止将它们用于绝大多数目标。通常没有足够的共同点来获得资格。请记住,我编写了 C++、ObjC、ObjC++ 和 C - 编译器为目标中的每个 lang 发出一个。因此启用它们通常会导致更慢的编译时间和更高的 I/O。归根结底,在复杂的项目中,增加依赖性并不是对抗依赖性的好方法。使用多种语言/方言,给定目标所需的依赖项有很大差异。不,我不建议将其作为每个项目的最佳选择,但这确实为大型项目中的依赖管理提供了一些视角。



References

参考



Notes

笔记

  • This question was originally asked a few years before Modules' introduction.
  • Presently (Xcode 5.0), modules work for C and ObjC, but not C++.
  • 这个问题最初是在 Modules 介绍前几年提出的。
  • 目前(Xcode 5.0),模块适用于 C 和 ObjC,但不适用于 C++。

回答by CIFilter

I agree with bbum. My take on the PCH file is that it should contain pretty much only #includeor #importstatements. So if you have a bunch of helpful, high-level macros, define them in something like Common.hand #importthat file, as bbum suggested.

我同意 bum 的观点。我对 PCH 文件的看法是它应该几乎只包含#includeor#import语句。因此,如果您有一堆有用的高级宏,请按照 bbum 的建议在类似Common.h#import该文件中定义它们。

I usually go a step further and use the PCH file to #importa file called XXCategories.h(where XXis the class naming prefix convention you use) that contains #imports for all my UIKit and Foundation class categories: NSString+XXAdditions.h, UIColor+XXAdditons.h, etc.

我通常走的更远了一步,并使用PCH文件到#import一个名为XXCategories.h(其中XX是使用class命名前缀约定),其中包含#import献给所有我的UIKit和基金类属:NSString+XXAdditions.hUIColor+XXAdditons.h,等。

回答by Leo Cavalcante

create an header file "macros.h"

创建头文件“macros.h”

import this header into Prefix.pch

将此标头导入 Prefix.pch

In this macros.h put all the frameworks and other important things.

在这个 macros.h 中放置了所有的框架和其他重要的东西。

If you are worried about performance, don't worry, look what apple says:

如果你担心性能,别担心,看看苹果是怎么说的:

Headers and Performance

标题和性能

If you are worried that including a master header file may cause your program to bloat, don't worry. Because OS X interfaces are implemented using frameworks, the code for those interfaces resides in a dynamic shared library and not in your executable. In addition, only the code used by your program is ever loaded into memory at runtime, so your in-memory footprint similarly stays small. As for including a large number of header files during compilation, once again, don't worry. Xcode provides a precompiled header facility to speed up compile times. By compiling all the framework headers at once, there is no need to recompile the headers unless you add a new framework. In the meantime, you can use any interface from the included frameworks with little or no performance penalty.

如果您担心包含主头文件可能会导致您的程序膨胀,请不要担心。因为 OS X 接口是使用框架实现的,这些接口的代码驻留在动态共享库中,而不是在您的可执行文件中。此外,只有您的程序使用的代码在运行时才会加载到内存中,因此您的内存占用同样很小。至于编译时包含大量的头文件,再次不用担心。Xcode 提供了一个预编译头工具来加快编译时间。通过一次编译所有框架头文件,除非添加新框架,否则无需重新编译头文件。同时,您可以使用包含框架中的任何接口,而几乎没有性能损失。

also in my macros.h I put a lot of constants like:

同样在我的 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];