Why isn't ProjectName-Prefix.pch created automatically in Xcode 6?
Asked Answered
R

8

265

Why isn't ProjectName-Prefix.pch created automatically in Xcode 6 ?

Is the precompile header no longer needed ?

Where should I write the code that was in ProjectName-Prefix.pch before ?

Rimarimas answered 11/6, 2014 at 8:57 Comment(0)
S
138

I suspect because of modules, which remove the need for the #import <Cocoa/Cocoa.h>.

As to where to put code that you would put in a prefix header, there is no code you should put in a prefix header. Put your imports into the files that need them. Put your definitions into their own files. Put your macros...nowhere. Stop writing macros unless there is no other way (such as when you need __FILE__). If you do need macros, put them in a header and include it.

The prefix header was necessary for things that are huge and used by nearly everything in the whole system (like Foundation.h). If you have something that huge and ubiquitous, you should rethink your architecture. Prefix headers make code reuse hard, and introduce subtle build problems if any of the files listed can change. Avoid them until you have a serious build time problem that you can demonstrate is dramatically improved with a prefix header.

In that case you can create one and pass it into clang, but it's incredibly rare that it's a good idea.


EDIT: To your specific question about a HUD you use in all your view controllers, yes, you should absolutely import it into every view controller that actually uses it. This makes the dependencies clear. When you reuse your view controller in a new project (which is common if you build your controllers well), you will immediately know what it requires. This is especially important for categories, which can make code very hard to reuse if they're implicit.

The PCH file isn't there to get rid of listing dependencies. You should still import UIKit.h or Foundation.h as needed, as the Xcode templates do. The reason for the PCH is to improve build times when dealing with really massive headers (like in UIKit).

Scrawly answered 12/6, 2014 at 22:37 Comment(20)
I agree to make the .pch file clean, but I'm confused in some situation, e.g. I use SVProgressHUD, almost all ViewController need to call it, so should I import SVProgressHUD.h in every ViewController ? or create a BaseViewController and import SVProgressHUD.h ? Categorys have the same situation. Could you give me any suggestion?Rimarimas
@Rob your answer is subjective rant. I do not agree it should be accepted as an answer for this question. How would you implement something like this github.com/seancook/TWReverseAuthExample/blob/… without pch ? Import the log into each and every file? This creates a whole pile of unnecessary bloat in your code.Entertaining
Each file that actually uses that macro, yes (in my experience this is usually less than every file in the system). This is a very good example of my point. Importing it implicitly masks the fact that you have a dependency on this logging macro. When you try to copy TWAPIManager.m, for example, to a another project, you'll get errors that TWALog() is not defined, with no hint about where to find it. I've encountered exactly that problem on several large projects trying to share code. Creating TWAPILog.h and importing it solves this with trivial dev cost.Scrawly
@RobNapier In the case of importing UIKit, though, what if you wanted to create a class that implements the UITableViewDelegate protocol? Would you @import UIKit for just that class, or would this be a necessary case for a PCH? Your answer, "as needed", isn't really clear.Friedcake
If you need UIKit functionality in a class, it import UIKit. If you don't, it should import Foundation. If you need AppKit functionality, you would import Cocoa. That keeps the code more reusable (I share a lot of code between iOS and OS X and recommend people not box themselves out of that for no purpose). You would still include UIKit in the PCH (when modules are not available), but only to improve build times.Scrawly
I use ReactiveCocoa in almost every class, it would be insane for me not to use a pch file...Pomace
I'm with Rob on this, importing where needed is the cleanest clearest path to managing dependencies. If you really need to manage things simpler, you probably want to look at your own Framework (still need to import that puppy where it is used) or even a module...Endocrinotherapy
Not only modules, but swift support is probably a big piece.Endocrinotherapy
@Rob How would you do Crash Reporting, like New Relic's without adding it to PCH? They really need to be in everything so you can see where the bug came from.Yawl
I don't see how crash reporting is related. Importing a header file just declares functions and classes for you. It doesn't actually cause anything to run. Do you make specific NewRelic calls in every single file? That would seem very strange. Looking at their docs, I only see one call required to their library (which is what I would expect). Have you tried without putting them in pch?Scrawly
How about categories? Imho, its stupid to have to import a dozen files or so in each view controller for example, if you happen to have a lot of categories.Triparted
The key is that PCH is a pre-compiled header. Pre-compilation is for build performance, not automatic availability. Pre-compilation introduces several ways to mess up your build, and should be reserved for huge things that never change between non-clean builds (like Foundation).Scrawly
Rob .. bizarre that you don't use Macros, buddy ! Programming without a preprocessor is like, uh, well it's no good.Lohrman
Everything else Rob says here is correct of course.Lohrman
What about macros to remove NSLog for a release configuration?Bedel
@Bedel I always use my own logging macro that can be removed or reconfigured in different configs. Put that macro in a header; import the header where you use it. Even if I believed in using pch for that kind of macro, I would never write a macro to redefine NSLog itself. Rewriting standard functions is very confusing.Scrawly
@Rob, I wanted to ask what should be done if there is let say a constants file, which I know will be used through out the project ? Is there an alternative to using prefix or using prefix for such a small file is ok ?Canaster
@Canaster generally constants should be kept together with the things they configure (in the same file, or in a closely related file imported by the configured object's header) and imported by those things they use them. In general, there shouldn't be a "system constants" file filled with unrelated constants. This is very harmful to code reuse. Most constants like "MySpecialColor" should be categories (on UIColor in this case). And styles and layouts should be passed as objects or active configurators that group related things when possible rather than relying on global standalone constants.Scrawly
@Rob, hmmm aight thanks, I think i got the gist of it.Canaster
Sure, Rob. like logging. DLog is certainly something that should go in a .pch, unless you offer an alternative. You state that modules make a pch irrelevant, but you don't say why. The convenience we want the .pch for is simply so that we DO NOT HAVE TO import another header everywhere for something we want to be available everywhere.Umont
C
427

Without the question if it is proper or not, you can add PCH file manually:

  1. Add new PCH file to the project: New file > Other > PCH file.

  2. At the Target's Build Settings option, set the value of Prefix Header to your PCH file name, with the project name as prefix (i.e. for project named TestProject and PCH file named MyPrefixHeaderFile, add the value TestProject/MyPrefixHeaderFile.pch to the plist).

    TIP: You can use things like $(SRCROOT) or $(PROJECT_DIR) to get to the path of where you put the .pch in the project.

  3. At the Target's Build Settings option, set the value of Precompile Prefix Header to YES.

Celik answered 17/6, 2014 at 7:34 Comment(8)
Despite my opinions on PCH files, +1. It is still useful for people to know how to use the tools.Scrawly
@Yedidya, I just wanted to say a quick thanks for taking the time to communicate the answer to the question despite whatever judgements you have about it. I appreciate when people take the time to cordially answer questions rather than just berate the person about how ill advised the question is.Lattimer
Thanks. I find it useful when incorporating some of my Objective-C into a Swift project, so I don't have to go back and add a bunch of include files to each of those .m files.Nordrheinwestfalen
Very handy when transitioning from ObjC to Swift - I have a heap of libraries written in ObjC and the last thing I want to do is edit all of them to include the right system headers.Amplexicaul
This didn't work for me cause I used the target's build settings. However, when I followed this instructinos modifying the Project Build Settings instead everything worked.Kalong
This is the real answer.Dissension
@Dissension no, it's not. This "answer" is useful but does not answer the OP's question: WHY isn't ProjectName-Prefix.pch created automatically in Xcode 6??Kingmaker
Prakash's answer is even better!Lohrman
S
138

I suspect because of modules, which remove the need for the #import <Cocoa/Cocoa.h>.

As to where to put code that you would put in a prefix header, there is no code you should put in a prefix header. Put your imports into the files that need them. Put your definitions into their own files. Put your macros...nowhere. Stop writing macros unless there is no other way (such as when you need __FILE__). If you do need macros, put them in a header and include it.

The prefix header was necessary for things that are huge and used by nearly everything in the whole system (like Foundation.h). If you have something that huge and ubiquitous, you should rethink your architecture. Prefix headers make code reuse hard, and introduce subtle build problems if any of the files listed can change. Avoid them until you have a serious build time problem that you can demonstrate is dramatically improved with a prefix header.

In that case you can create one and pass it into clang, but it's incredibly rare that it's a good idea.


EDIT: To your specific question about a HUD you use in all your view controllers, yes, you should absolutely import it into every view controller that actually uses it. This makes the dependencies clear. When you reuse your view controller in a new project (which is common if you build your controllers well), you will immediately know what it requires. This is especially important for categories, which can make code very hard to reuse if they're implicit.

The PCH file isn't there to get rid of listing dependencies. You should still import UIKit.h or Foundation.h as needed, as the Xcode templates do. The reason for the PCH is to improve build times when dealing with really massive headers (like in UIKit).

Scrawly answered 12/6, 2014 at 22:37 Comment(20)
I agree to make the .pch file clean, but I'm confused in some situation, e.g. I use SVProgressHUD, almost all ViewController need to call it, so should I import SVProgressHUD.h in every ViewController ? or create a BaseViewController and import SVProgressHUD.h ? Categorys have the same situation. Could you give me any suggestion?Rimarimas
@Rob your answer is subjective rant. I do not agree it should be accepted as an answer for this question. How would you implement something like this github.com/seancook/TWReverseAuthExample/blob/… without pch ? Import the log into each and every file? This creates a whole pile of unnecessary bloat in your code.Entertaining
Each file that actually uses that macro, yes (in my experience this is usually less than every file in the system). This is a very good example of my point. Importing it implicitly masks the fact that you have a dependency on this logging macro. When you try to copy TWAPIManager.m, for example, to a another project, you'll get errors that TWALog() is not defined, with no hint about where to find it. I've encountered exactly that problem on several large projects trying to share code. Creating TWAPILog.h and importing it solves this with trivial dev cost.Scrawly
@RobNapier In the case of importing UIKit, though, what if you wanted to create a class that implements the UITableViewDelegate protocol? Would you @import UIKit for just that class, or would this be a necessary case for a PCH? Your answer, "as needed", isn't really clear.Friedcake
If you need UIKit functionality in a class, it import UIKit. If you don't, it should import Foundation. If you need AppKit functionality, you would import Cocoa. That keeps the code more reusable (I share a lot of code between iOS and OS X and recommend people not box themselves out of that for no purpose). You would still include UIKit in the PCH (when modules are not available), but only to improve build times.Scrawly
I use ReactiveCocoa in almost every class, it would be insane for me not to use a pch file...Pomace
I'm with Rob on this, importing where needed is the cleanest clearest path to managing dependencies. If you really need to manage things simpler, you probably want to look at your own Framework (still need to import that puppy where it is used) or even a module...Endocrinotherapy
Not only modules, but swift support is probably a big piece.Endocrinotherapy
@Rob How would you do Crash Reporting, like New Relic's without adding it to PCH? They really need to be in everything so you can see where the bug came from.Yawl
I don't see how crash reporting is related. Importing a header file just declares functions and classes for you. It doesn't actually cause anything to run. Do you make specific NewRelic calls in every single file? That would seem very strange. Looking at their docs, I only see one call required to their library (which is what I would expect). Have you tried without putting them in pch?Scrawly
How about categories? Imho, its stupid to have to import a dozen files or so in each view controller for example, if you happen to have a lot of categories.Triparted
The key is that PCH is a pre-compiled header. Pre-compilation is for build performance, not automatic availability. Pre-compilation introduces several ways to mess up your build, and should be reserved for huge things that never change between non-clean builds (like Foundation).Scrawly
Rob .. bizarre that you don't use Macros, buddy ! Programming without a preprocessor is like, uh, well it's no good.Lohrman
Everything else Rob says here is correct of course.Lohrman
What about macros to remove NSLog for a release configuration?Bedel
@Bedel I always use my own logging macro that can be removed or reconfigured in different configs. Put that macro in a header; import the header where you use it. Even if I believed in using pch for that kind of macro, I would never write a macro to redefine NSLog itself. Rewriting standard functions is very confusing.Scrawly
@Rob, I wanted to ask what should be done if there is let say a constants file, which I know will be used through out the project ? Is there an alternative to using prefix or using prefix for such a small file is ok ?Canaster
@Canaster generally constants should be kept together with the things they configure (in the same file, or in a closely related file imported by the configured object's header) and imported by those things they use them. In general, there shouldn't be a "system constants" file filled with unrelated constants. This is very harmful to code reuse. Most constants like "MySpecialColor" should be categories (on UIColor in this case). And styles and layouts should be passed as objects or active configurators that group related things when possible rather than relying on global standalone constants.Scrawly
@Rob, hmmm aight thanks, I think i got the gist of it.Canaster
Sure, Rob. like logging. DLog is certainly something that should go in a .pch, unless you offer an alternative. You state that modules make a pch irrelevant, but you don't say why. The convenience we want the .pch for is simply so that we DO NOT HAVE TO import another header everywhere for something we want to be available everywhere.Umont
R
129

You need to create own PCH file
Add New file -> Other-> PCH file

Then add the path of this PCH file to your build setting->prefix header->path

($(SRCROOT)/filename.pch)

enter image description here

Rockbottom answered 2/7, 2014 at 6:56 Comment(2)
Well, depending on the working dir, variables could vary. I am using $(PRODUCT_DIR)/$(PRODUCT_NAME)/PrefixHeader.pchKingmaker
If you keep the .pch file within the particular folder, then the situation occurred.Rockbottom
E
51

I'll show you with a pic!

  1. Add a new File Add a new File

  2. Go to Project/Build Setting/APPl LLVM 6.0-Language Add a new File

Ectoparasite answered 5/1, 2015 at 7:46 Comment(0)
M
24

To add .pch file-

1) Add new .pch file to your project->New file->other->PCH file

2) Goto your project's build setting.

3) Search "prefix header". You can find that under Apple LLVM.

4) Paste this in the field $(SRCROOT)/yourPrefixHeaderFileName.pch

5) Clean and build the project. That's it!!!

enter image description here

Mercaptide answered 13/11, 2014 at 16:18 Comment(0)
A
12

If you decide to add a .pch file manually and you want to use Objective-C just like before xCode 6 you will also have to import UIKit and Foundation frameworks in the .pch file. Otherwise you will have to import these frameworks manually in each header file. You can add the following code anyway as it tests for the language used:

#ifdef __OBJC__
    #import <UIKit/UIKit.h>
    #import <Foundation/Foundation.h>
#endif
Avuncular answered 10/12, 2014 at 12:4 Comment(1)
Everything which involves ObjC code must be wrapped inside the above #ifdef _ OBJC _, otherwise you will get errors from C sources (in case you have such sources) that you will never understandInventive
S
7

For add new PCH file follow bellow steps :

(1) Add New fiew - Select iOS - Other and PCH File

(2) add path of this PCH file to your Project - BuildSetting - Apple LLVM 6.0 Language

Add Set Prefix Header Path YourApplicationName(root-path)/filename.pch

Storer answered 29/9, 2014 at 7:56 Comment(1)
Kindly explain the last one. Add set prefix header path.Rumpf
C
7

Use :

$(PROJECT_DIR)/Project name/PrefixHeader.pch

Camail answered 3/2, 2015 at 22:31 Comment(1)
Does any $ kind of declaration exists for "Project Name" ??Leonidaleonidas

© 2022 - 2024 — McMap. All rights reserved.