Các phương pháp hay nhất cho iOS Prefix.pch


90

Tôi đã thấy nhiều nhà phát triển thêm nhiều macro tiện lợi khác nhau vào Prefix.pch trong các dự án iOS của họ.

Bạn nên làm gì (hoặc không) bạn nên thêm vào tệp Prefix.pch iOS? Prefix.pch của bạn trông như thế nào?


Một bài chi tiết trên blog về chủ đề này: cimgf.com/2010/05/02/my-current-prefix-pch-file
hpique

2
Ví dụ: chỉ cần đặt macro của bạn vào tệp tiêu đề Macros.h, rồi nhập tệp này vào tệp của bạn prefix.pch.
Malloc

Tôi cũng đang phải đối mặt với cùng một vấn đề ... làm thế nào để giải quyết trong Xcode 6.1
Yalamandarao

Câu trả lời:


121

Ewww… đừng đặt macro trong tệp .pch! Theo định nghĩa, tệp .pch là tiêu đề được biên dịch trước của một dự án cụ thể. Nó thực sự không nên được sử dụng ngoài ngữ cảnh của dự án và nó thực sự không nên chứa bất cứ thứ gì ngoài #includes và #imports.

Nếu bạn có một số macro và những macro như vậy mà bạn muốn chia sẻ giữa các tiêu đề, thì hãy gắn chúng vào tệp tiêu đề của riêng chúng - Common.hhoặc bất cứ thứ gì - và #include cái đó ở đầu .pch.


Bạn sẽ bao gồm những gì trong Common.h đó?
hpique

4
Không có gì; Tôi chỉ đặt các #defines khác nhau, v.v. ... vào đó.
bbum

37

Đối với iOS và OS X hiện đại, mọi người nên sử dụng Mô-đun . Điều này được bật theo mặc định cho các dự án mới và việc nhập / đưa vào được hoàn thành bằng cách sử dụng @import.

Các mô-đun cho phép trình biên dịch tạo ra một biểu diễn trung gian của nội dung của một mô-đun (ví dụ: tiêu đề của khung). Giống như PCH, phần trình bày trung gian này có thể được chia sẻ trên nhiều bản dịch. Nhưng các mô-đun tiến thêm một bước nữa bởi vì một mô-đun không nhất thiết phải nhắm mục tiêu cụ thể và các khai báo của chúng không cần được bản địa hóa (thành a *.pch). Biểu diễn này có thể giúp bạn tiết kiệm rất nhiều công việc biên dịch dư thừa.

Sử dụng các mô-đun, bạn không cần PCH, và có lẽ bạn chỉ nên loại bỏ chúng hoàn toàn - có lợi cho việc sử dụng @importcục bộ cho phần phụ thuộc. Trong trường hợp đó, PCH chỉ giúp bạn không phải nhập bao gồm cục bộ vào các phụ thuộc (IMO mà bạn vẫn nên làm).

Bây giờ, nếu chúng ta quay lại câu hỏi ban đầu: Bạn nên tránh điền vào PCH của mình với tất cả những thứ ngẫu nhiên; Macro, hằng số #definesvà tất cả các loại thư viện nhỏ. Nói chung, bạn nên bỏ qua những gì thực sự không cần thiết đối với phần lớn các tệp nguồn của mình . Đưa tất cả các loại nội dung vào PCH của bạn chỉ là thêm một loạt trọng lượng và sự phụ thuộc. Tôi thấy mọi người đưa mọi thứ họ liên kết và hơn thế nữa vào PCH. Trong thực tế, các khung phụ trợ thường chỉ cần hiển thị cho một vài bản dịch trong hầu hết các trường hợp. Ví dụ: "Đây là nội dung StoreKit của chúng tôi - hãy chỉ nhập StoreKit ở nơi nó phảiđược hiển thị. Cụ thể là 3 bản dịch này ". Điều này giúp giảm thời gian xây dựng của bạn và giúp bạn theo dõi các phần phụ thuộc của mình, để bạn có thể sử dụng lại mã dễ dàng hơn. Vì vậy, trong một dự án objC, bạn thường dừng lại ở Foundation. Nếu có nhiều giao diện người dùng, sau đó bạn có thể cân nhắc thêm UIKit hoặc AppKit vào PCH của mình. Tất cả điều này giả sử bạn muốn tối ưu hóa thời gian xây dựng. Một trong những vấn đề với PCH lớn bao gồm (gần như) mọi thứ là việc loại bỏ các phụ thuộc không cần thiết sẽ rất mất thời gian. Một lần sự phụ thuộc của dự án của bạn tăng lên và thời gian xây dựng của bạn tăng lên, bạn cần phải chống lại bằng cách loại bỏ những phụ thuộc không cần thiết để giảm thời gian xây dựng của bạn. Ngoài ra, bất kỳ điều gì thay đổi thường xuyên thường phải được loại trừ khỏi PCH của bạn. Một thay đổi yêu cầu phải xây dựng lại toàn bộ. Có một số tùy chọn để chia sẻ PCH. Nếu bạn sử dụng PCH,

Theo như những gì tôi đưa ra trong PCH của mình: Tôi đã ngừng sử dụng chúng cho phần lớn các mục tiêu cách đây nhiều năm. Chỉ có thường là không đủ chung để đủ điều kiện. Hãy nhớ rằng, tôi viết C ++, ObjC, ObjC ++ và C - trình biên dịch tạo ra một cho mỗi ngôn ngữ trong mục tiêu của bạn. Vì vậy, việc kích hoạt chúng thường dẫn đến thời gian biên dịch chậm hơn và I / O cao hơn. Cuối cùng, gia tăng sự phụ thuộc không phải là một cách tốt để chống lại sự phụ thuộc trong các dự án phức tạp. Làm việc với nhiều ngôn ngữ / phương ngữ, có nhiều sự thay đổi trong các phụ thuộc cần thiết cho một mục tiêu nhất định. Không, tôi sẽ không khuyên rằng điều đó là tối ưu cho mọi dự án, nhưng điều đó đưa ra một số quan điểm về quản lý sự phụ thuộc trong các dự án lớn hơn.


Người giới thiệu


Ghi chú

  • Câu hỏi này ban đầu được hỏi một vài năm trước khi giới thiệu Mô-đun.
  • Hiện tại (Xcode 5.0), các mô-đun hoạt động với C và ObjC, nhưng không hoạt động với C ++.

Nó có nghĩa là gì khi xây dựng lại hoàn toàn cho một dự án hỗ trợ mô-đun. Bạn biết đấy, tiêu đề bắc cầu -Swift.h mới này chắc chắn không phải là ứng cử viên phù hợp cho .pch. Nhưng tôi đã thấy mọi người làm điều đó. Vì vậy, như bạn có thể thấy nếu ai đó làm điều đó. Chúng tôi có một tiêu đề luôn thay đổi trong .pch. Vì vậy, nó xây dựng lại mọi thứ trong tệp .pch mỗi khi -Swift.h được tạo lại. Bạn có đồng ý với điều này? Bạn có nhiều đầu vào hơn?
MadNik

@MadNik Giả sử PCH của ứng dụng của bạn bao gồm tiêu đề chính của thư viện / khuôn khổ mà bạn đang tích cực phát triển. Ví dụ: #import "MyLib/MyLib.h". Bất cứ khi nào một tệp được bao gồm bởi các MyLib.hthay đổi, mọi tệp nguồn trong ứng dụng phải được biên dịch lại. Nếu bạn sử dụng MyLib chỉ trong một tệp nguồn, thì chỉ tệp đó phải được biên dịch lại khi MyLib thay đổi. Tin hay không thì tùy, tôi không sử dụng bất kỳ tệp PCH nào trong những ngày này.
justin

8

Tôi đồng ý với bbum. Ý kiến ​​của tôi về tệp PCH là nó chỉ nên chứa khá nhiều chỉ #includehoặc các #importcâu lệnh. Vì vậy, nếu bạn có một loạt các macro hữu ích, cấp cao, hãy xác định chúng trong một cái gì đó tương tự Common.h#importtệp đó, như bbum đã đề xuất.

Tôi thường đi một bước xa hơn và sử dụng các tập tin PCH đến #importmột tập tin gọi là XXCategories.h(nơi XXlà lớp quy ước đặt tên tiền tố bạn sử dụng) có chứa #imports cho tất cả UIKit tôi và lớp Foundation loại: NSString+XXAdditions.h, UIColor+XXAdditons.hvv


Tôi chỉ tò mò. Trong tệp .PCH, sự khác biệt giữa việc nhập Common.h có nhiều tệp khác nhau #importvà chỉ nhập #importtrực tiếp những tệp đó ? Những điều đó sẽ không giống nhau ?, hay nó có ảnh hưởng đến hiệu suất nào không?
Hlung

Theo hiểu biết của tôi, không có sự khác biệt thực sự. Tôi đoán đó là một phương pháp hay nhất. Thay vì đưa một loạt macro và những thứ khác vào tệp PCH của bạn, nó chỉ nên dành cho #import#include.
CIFilter

1
Sự khác biệt là khả năng tái sử dụng. PCH là dự án cụ thể. Common.h sẽ phổ biến cho nhiều dự án. Nó giống như việc hỏi tại sao bạn không chỉ đặt tất cả các lớp sử dụng vào dự án của mình thay vì tạo một dự án con mà bạn có thể sử dụng lại. Mặc dù là một ví dụ giả tạo, bởi vì nó chỉ là một thao tác sao chép đơn giản ... nhưng sao chép dán thì thật là nghịch ngợm.
bandejapaisa

6

tạo tệp tiêu đề "macros.h"

nhập tiêu đề này vào Prefix.pch

Trong macro.h này đặt tất cả các khuôn khổ và những thứ quan trọng khác.

Nếu bạn lo lắng về hiệu suất, đừng lo lắng, hãy nhìn những gì apple nói:

Tiêu đề và Hiệu suất

Nếu bạn lo lắng rằng việc bao gồm một tệp tiêu đề chính có thể khiến chương trình của bạn bị cồng kềnh, đừng lo lắng. Vì các giao diện OS X được triển khai bằng cách sử dụng các khuôn khổ, mã cho các giao diện đó nằm trong một thư viện được chia sẻ động chứ không phải trong tệp thực thi của bạn. Ngoài ra, chỉ có mã được chương trình của bạn sử dụng mới được tải vào bộ nhớ trong thời gian chạy, vì vậy dấu chân trong bộ nhớ của bạn tương tự vẫn nhỏ. Đối với việc bao gồm một số lượng lớn các tệp tiêu đề trong quá trình biên dịch, một lần nữa, đừng lo lắng. Xcode cung cấp cơ sở tiêu đề được biên dịch trước để tăng tốc thời gian biên dịch. Bằng cách biên dịch tất cả các tiêu đề khung cùng một lúc, không cần phải biên dịch lại các tiêu đề trừ khi bạn thêm một khung mới. Trong thời gian chờ đợi, bạn có thể sử dụng bất kỳ giao diện nào từ các khuôn khổ đi kèm mà ít hoặc không bị phạt về hiệu suất.

cũng trong macro.h của tôi, tôi đặt rất nhiều hằng số như:

// 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
Một hữu ích ở đây: #define async(...) dispatch_async(dispatch_get_main_queue(), __VA_ARGS__ )... để chạy khối trên các chủ đề chính:async(^{ self.someLabel.text = @":D"; });
Alejandro Iván
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.