Praktik terbaik iOS Prefix.pch

90

Saya telah melihat banyak pengembang yang menambahkan berbagai makro kemudahan ke Prefix.pch proyek iOS mereka.

Apa yang (atau tidak) Anda rekomendasikan untuk ditambahkan ke file iOS Prefix.pch? Seperti apa Prefix.pch Anda?

hpique
sumber
Entri blog terperinci tentang subjek: cimgf.com/2010/05/02/my-current-prefix-pch-file
hpique
2
Cukup letakkan makro Anda ke dalam file header, misalnya Macros.h, lalu impor file ini ke file prefix.pch.
Malloc
Saya juga menghadapi masalah yang sama ... bagaimana menyelesaikan di Xcode 6.1
Yalamandarao

Jawaban:

121

Ewww… jangan letakkan makro dalam file .pch! File .pch, menurut definisi, adalah header khusus proyek yang telah dikompilasi. Ini benar-benar tidak boleh digunakan di luar konteks proyek dan tidak boleh berisi apa pun kecuali #includes dan#import s.

Jika Anda memiliki beberapa makro dan yang ingin Anda bagi di antara header, maka tempelkan di file header mereka sendiri - Common.hatau apa pun - dan #include itu di awal .pch.

bbum
sumber
Apa yang akan Anda masukkan dalam Common.h itu?
hpique
4
Tidak ada; Saya hanya akan memasukkan berbagai #definisi, dll ... di dalamnya.
bbum
37

Untuk iOS dan OS X modern, orang harus menggunakan Modul . Ini diaktifkan secara default untuk proyek baru, dan pengimporan / penyertaan dilakukan dengan menggunakan @import.

Modul memungkinkan kompilator untuk membuat representasi perantara dari konten modul (misalnya header kerangka kerja). Sama seperti PCH, representasi perantara ini dapat dibagikan ke berbagai terjemahan. Tetapi modul mengambil satu langkah lebih jauh karena modul belum tentu spesifik target, dan deklarasinya tidak perlu dilokalkan (ke a *.pch). Representasi ini dapat menghemat banyak pekerjaan kompilator yang berlebihan.

Dengan menggunakan modul, Anda tidak memerlukan PCH, dan Anda mungkin harus menghapusnya sepenuhnya - mendukung penggunaan @importlokal ke dependensi. Dalam hal ini, PCH hanya menyelamatkan Anda dari mengetik inklusi lokal ke dependensi (yang tetap harus Anda lakukan IMO).

Sekarang, jika kita melihat kembali ke pertanyaan awal: Anda harus menghindari mengisi PCH Anda dengan segala macam hal acak; Makro, konstanta, #definesdan semua jenis perpustakaan kecil. Umumnya, Anda harus menghilangkan apa yang sebenarnya tidak diperlukan untuk sebagian besar file sumber Anda . Menempatkan segala macam barang di PCH Anda hanya menambah banyak beban dan ketergantungan. Saya melihat orang-orang meletakkan semua yang mereka tautkan dan lebih banyak lagi ke PCH. Pada kenyataannya, kerangka kerja tambahan biasanya hanya perlu terlihat oleh beberapa terjemahan dalam banyak kasus. Misalnya "Ini barang StoreKit kami - mari impor StoreKit hanya di tempat yang seharusnyaterlihat. Khususnya, 3 terjemahan ini ". Ini membuat waktu build Anda turun, dan membantu Anda melacak dependensi Anda, sehingga Anda dapat menggunakan kembali kode dengan lebih mudah. ​​Jadi dalam proyek ObjC, Anda biasanya berhenti di Foundation. Jika ada banyak UI, maka Anda dapat mempertimbangkan untuk menambahkan UIKit atau AppKit ke PCH Anda. Ini semua dengan asumsi Anda ingin mengoptimalkan waktu build. Salah satu masalah dengan PCH besar yang mencakup (hampir) semuanya adalah menghapus dependensi yang tidak perlu sangat memakan waktu. Sekali Ketergantungan proyek Anda bertambah dan waktu pembangunan Anda meningkat, Anda perlu melawan dengan menghilangkan ketergantungan yang tidak perlu untuk mengurangi waktu pembangunan Anda. Selain itu, segala sesuatu yang sering berubah umumnya harus dijauhkan dari PCH Anda. Perubahan memerlukan pembangunan kembali sepenuhnya. Ada beberapa opsi untuk berbagi PCH. Jika Anda menggunakan PCH,

Sejauh yang saya masukkan ke PCH saya: Saya berhenti menggunakannya untuk sebagian besar target tahun lalu. Biasanya tidak ada cukup kesamaan untuk memenuhi syarat. Ingatlah, saya menulis C ++, ObjC, ObjC ++ dan C - kompilator mengeluarkan satu untuk setiap bahasa dalam target Anda. Jadi mengaktifkannya sering kali menghasilkan waktu kompilasi yang lebih lambat dan I / O yang lebih tinggi. Pada akhirnya, meningkatkan ketergantungan bukanlah cara yang baik untuk melawan ketergantungan dalam proyek yang kompleks. Bekerja dengan banyak bahasa / dialek, ada banyak variasi dalam ketergantungan yang diperlukan untuk target tertentu. Tidak, saya tidak menyarankan itu seoptimal untuk setiap proyek, tetapi itu memberikan beberapa perspektif untuk manajemen ketergantungan dalam proyek yang lebih besar.


Referensi


Catatan

  • Pertanyaan ini awalnya ditanyakan beberapa tahun sebelum pengenalan Modul.
  • Saat ini (Xcode 5.0), modul berfungsi untuk C dan ObjC, tetapi tidak C ++.
justin
sumber
Apa yang dimaksud dengan pembangunan kembali lengkap untuk proyek yang mendukung modul. Anda tahu bahwa header bridging -Swift.h baru ini jelas bukan kandidat yang tepat untuk .pch. Tetapi saya telah melihat orang-orang melakukan itu. Jadi seperti yang Anda lihat jika seseorang melakukan itu. Kami memiliki header yang selalu berubah di .pch. Jadi itu membangun kembali semua yang ada di file .pch setiap kali -Swift.h dibuat ulang. Apakah kamu setuju dengan ini? Anda memiliki lebih banyak masukan?
MadNik
@MadNik Misalkan PCH aplikasi Anda menyertakan header master dari pustaka / kerangka kerja yang sedang Anda kembangkan secara aktif. Sebagai contoh: #import "MyLib/MyLib.h". Setiap kali file disertakan oleh MyLib.hperubahan, setiap file sumber dalam aplikasi harus dikompilasi ulang. Jika Anda menggunakan MyLib hanya dalam satu file sumber, maka hanya file itu yang harus dikompilasi ulang saat MyLib berubah. Percaya atau tidak, saya tidak menggunakan file PCH hari ini.
justin
8

Saya setuju dengan bbum. Pandangan saya tentang file PCH adalah bahwa file tersebut harus berisi cukup banyak saja #includeatau #importpernyataan. Jadi, jika Anda memiliki banyak makro tingkat tinggi yang bermanfaat, tentukan mereka dalam sesuatu seperti Common.hdan #importfile itu, seperti yang disarankan bbum.

Saya biasanya melangkah lebih jauh dan menggunakan file PCH untuk #importsebuah file bernama XXCategories.h(di mana XXadalah kelas konvensi penamaan awalan yang Anda gunakan) yang berisi #imports untuk semua kategori UIKit saya dan kelas Yayasan: NSString+XXAdditions.h, UIColor+XXAdditons.h, dll

CIFilter
sumber
Saya hanya penasaran. Di file .PCH, apa perbedaan antara mengimpor Common.h yang memiliki variasi #importdan hanya mengimpornya #importsecara langsung? Bukankah itu sama ?, atau apakah itu memengaruhi kinerja apa pun?
Hlung
Sepengetahuan saya, tidak ada perbedaan nyata . Ini lebih merupakan praktik terbaik, saya kira. Daripada memasukkan banyak makro dan hal-hal lain ke dalam file PCH Anda, itu seharusnya hanya untuk #importdan #include.
CIFilter
1
Perbedaannya adalah kegunaan kembali. PCH adalah proyek khusus. Common.h akan menjadi hal yang umum untuk banyak proyek. Ini mirip dengan menanyakan mengapa Anda tidak hanya memasukkan semua kelas util Anda ke dalam proyek Anda alih-alih membuat sub proyek yang dapat Anda gunakan kembali. Meskipun contoh yang dibuat-buat, karena itu hanya copy paste sederhana ... tapi copy paste itu nakal.
bandejapaisa
6

buat file header "macros.h"

impor header ini ke Prefix.pch

Di macro.h ini meletakkan semua framework dan hal penting lainnya.

Jika Anda khawatir tentang kinerja, jangan khawatir, lihat apa yang dikatakan apel:

Header dan Performa

Jika Anda khawatir bahwa menyertakan file header master dapat menyebabkan program Anda membengkak, jangan khawatir. Karena antarmuka OS X diimplementasikan menggunakan kerangka kerja, kode untuk antarmuka tersebut berada di pustaka bersama dinamis dan bukan di file yang dapat dieksekusi. Selain itu, hanya kode yang digunakan oleh program Anda yang pernah dimuat ke dalam memori saat runtime, sehingga jejak dalam memori Anda juga tetap kecil. Adapun memasukkan sejumlah besar file header selama kompilasi, sekali lagi, jangan khawatir. Xcode menyediakan fasilitas header yang telah dikompilasi untuk mempercepat waktu kompilasi. Dengan mengompilasi semua header framework sekaligus, Anda tidak perlu mengompilasi ulang header kecuali Anda menambahkan framework baru. Sementara itu, Anda dapat menggunakan antarmuka apa pun dari kerangka yang disertakan dengan sedikit atau tanpa penalti kinerja.

juga di macros.h saya, saya meletakkan banyak konstanta seperti:

// 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];
Leo Cavalcante
sumber
2
Hal lain yang berguna di sini: #define async(...) dispatch_async(dispatch_get_main_queue(), __VA_ARGS__ )... untuk menjalankan blok di utas utama:async(^{ self.someLabel.text = @":D"; });
Alejandro Iván