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

답변:


121

Ewww… .pch 파일에 매크로를 넣지 마십시오! .pch 파일은 정의에 따라 프로젝트 별 미리 컴파일 된 헤더입니다. 프로젝트의 맥락을 넘어서서 사용해서는 안되며 #includes와 #imports 만 포함하면 안됩니다 .

당신은 몇 가지 매크로를 가지고 같은 당신은 자신의 헤더 파일에 그들을 스틱, 헤더 사이에 공유하고자하는 경우 - Common.h및 - 또는 어떤 #include 것을 .PCH의 시작 부분에.


Common.h에 무엇을 포함 하시겠습니까?
hpique

4
아무것도; 다양한 #defines 등을 넣을 것입니다.
bbum

37

최신 iOS 및 OS X의 경우 사람들은 Modules를 사용해야합니다 . 이것은 새 프로젝트에 대해 기본적으로 활성화되며 가져 오기 / 포함은 @import.

모듈을 사용하면 컴파일러가 모듈 내용 (예 : 프레임 워크의 헤더)의 중간 표현을 만들 수 있습니다. PCH와 매우 유사하게이 중간 표현은 여러 번역에서 공유 될 수 있습니다. 그러나 모듈은 특정 대상이 아닐 수도 있고 선언을 지역화 할 필요가 없기 때문에 한 단계 더 나아갑니다 *.pch. 이 표현은 당신에게 많은 중복 컴파일러 작업을 절약 할 수 있습니다.

모듈을 사용하면 PCH가 필요하지 않으며 @import종속성에 대한 로컬 사용을 선호하여 모듈을 완전히 제거해야합니다 . 이 경우, PCH 만에서 당신을 절약 타이핑 (IMO 어쨌든 일을해야) 종속 로컬 흠.

이제 원래의 질문으로 돌아가 보면 : PCH를 모든 종류의 무작위로 채우는 것을 피해야합니다. 매크로, 상수, #defines및 모든 종류의 작은 라이브러리. 일반적으로 대부분의 소스 파일에 실제로 불필요한 것은 생략 해야 합니다 . PCH에 모든 종류의 물건을 넣는 것은 무게와 의존성을 추가하는 것입니다. 나는 사람들이 그들이 연결하는 모든 것을 PCH에 넣는 것을 봅니다. 실제로 보조 프레임 워크는 일반적으로 대부분의 경우 몇 개의 번역에만 표시되어야합니다. 예는 "여기에 우리의 StoreKit 물건입니다 -하자의 수입 StoreKit 경우에만이 해야볼 수 있습니다. 특히,이 3 가지 번역 ". 이렇게하면 빌드 시간이 단축되고 종속성을 추적하는 데 도움이되므로 코드를 더 쉽게 재사용 할 수 있습니다. 따라서 ObjC 프로젝트에서는 일반적으로 Foundation에서 멈출 것입니다. UIKit 또는 AppKit을 PCH에 추가하는 것을 고려할 수 있습니다. 이는 모두 빌드 시간을 최적화하려는 경우입니다. 거의 모든 것을 포함하는 대형 PCH의 문제 중 하나는 불필요한 종속성을 제거하는 데 시간이 많이 걸린다는 것입니다. 프로젝트의 종속성이 증가하고 빌드 시간이 늘어 나면 빌드 시간을 줄이기 위해 불필요한 종속성을 제거하여 맞서 싸워야합니다. 또한 자주 변경되는 항목은 일반적으로 PCH에서 제외되어야합니다. 변경하려면 전체를 다시 빌드해야합니다. PCH를 공유하는 몇 가지 옵션이 있습니다. PCH를 사용하는 경우

PCH에 입력 한 내용에 대해서는 몇 년 전에 대부분의 대상에 대해 사용을 중단했습니다. 일반적으로 공통점이 충분하지 않습니다. 명심하세요, 저는 C ++, ObjC, ObjC ++ 및 C를 작성합니다. 컴파일러는 타겟의 각 언어에 대해 하나씩 내 보냅니다. 따라서이를 활성화하면 종종 컴파일 시간이 느려지고 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를 사용하는 경우 MyLib가 변경 될 때 해당 파일 만 다시 컴파일해야합니다. 믿거 나 말거나 요즘에는 PCH 파일을 사용하지 않습니다.
justin

8

나는 bbum에 동의합니다. PCH 파일에 대한 필자의 견해는 #include또는 #import진술 만 포함해야한다는 것 입니다. 당신이 도움이, 높은 수준의 매크로 무리가 있다면 그래서, 같은 뭔가를 정의 Common.h하고 #importbbum 제안으로, 해당 파일.

나는 보통 한 단계 더 나아가 PCH 파일을 사용하여 #import 이라는 파일 XXCategories.h(여기서 XX포함 사용하는 클래스 이름 접두사 규칙입니다) #import내 모든 UIKit 및 기초 클래스 범주들 : NSString+XXAdditions.h, UIColor+XXAdditons.h, 등


그냥 궁금 해요. .PCH 파일에서 다양한 Common.h #import가져 오기와 #import직접 가져 오기의 차이점은 무엇 입니까? 동일하지 않습니까? 아니면 성능에 영향을 미칩니 까?
Hlung

내가 아는 한, 실제 차이는 없습니다 . 모범 사례에 가깝습니다. 많은 매크로 및 기타 항목을 PCH 파일에 밀어 넣는 대신 #import#include.
CIFilter

1
차이점은 재사용 가능성입니다. PCH는 프로젝트별로 다릅니다. Common.h는 많은 프로젝트에 공통적입니다. 재사용 할 수있는 하위 프로젝트를 만드는 대신 모든 util 클래스를 프로젝트에 넣지 않는 이유를 묻는 것과 비슷합니다. 단순한 복사 붙여 넣기이기 때문에 인위적인 예이지만 복사 붙여 넣기는 장난 스럽습니다.
bandejapaisa 2013-06-20

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"; });
알레한드로 이반
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.