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?
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?
Macros.h
, rồi nhập tệp này vào tệp của bạn prefix.pch
.
Câu trả lời:
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 #include
s và #import
s.
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.h
hoặc bất cứ thứ gì - và #include
cái đó ở đầu .pch.
Đố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 @import
cụ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ố #defines
và 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ú
#import "MyLib/MyLib.h"
. Bất cứ khi nào một tệp được bao gồm bởi các MyLib.h
thay đổ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.
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ỉ #include
hoặc các #import
câ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
và #import
tệ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 #import
một tập tin gọi là XXCategories.h
(nơi XX
là lớp quy ước đặt tên tiền tố bạn sử dụng) có chứa #import
s cho tất cả UIKit tôi và lớp Foundation loại: NSString+XXAdditions.h
, UIColor+XXAdditons.h
vv
#import
và chỉ nhập #import
trự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?
#import
và #include
.
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];
#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"; });