Практичні поради щодо iOS Prefix.pch


90

Я бачив багато розробників, які додають різні макроси зручності до Prefix.pch своїх проектів iOS.

Що (або ні) ви рекомендуєте додавати до файлу iOS Prefix.pch? Як виглядає ваш Prefix.pch?


Детальний допис у блозі на цю тему: cimgf.com/2010/05/02/my-current-prefix-pch-file
hpique

2
Просто вставте свої макроси, наприклад, у заголовочний файл Macros.h, а потім імпортуйте цей файл у свій prefix.pch.
Malloc

Я також стикаюся з такою ж проблемою ... як вирішити в Xcode 6.1
Яламандарао

Відповіді:


121

Ewww ... не вкладайте макроси у файл .pch! Файл .pch, за визначенням, є попередньо скомпільованим заголовком проекту. Його справді не слід використовувати поза контекстом проекту, і він насправді не повинен містити нічого, крім #includes та #imports.

Якщо у вас є деякі макроси та такі, якими ви хочете поділитися між заголовками, то вставте їх у власний файл заголовка - Common.hабо що завгодно - і #include це на початку .pch.


Що б ви включили до цього Common.h?
hpique

4
Нічого; Я б вклав у нього лише різні #defines тощо.
bbum

37

Для сучасних iOS та OS X люди повинні використовувати модулі . Це ввімкнено за замовчуванням для нових проектів, а імпорт / включення здійснюється за допомогою @import.

Модулі дозволяють компілятору створювати проміжне представлення вмісту модуля (наприклад, заголовки фреймворку). Як і PCH, це проміжне подання може бути спільним для кількох перекладів. Але модулі роблять цей крок далі, оскільки модуль не обов'язково є цільовим, і їх оголошення не потрібно локалізувати (до a *.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 - компілятор видає по одному для кожного lang у вашій цілі. Тому їх увімкнення часто призводило до повільнішого часу компіляції та вищих входів / виходів. Зрештою, збільшення залежності не є хорошим способом боротьби із залежністю в складних проектах. Працюючи з кількома мовами / діалектами, існує значна різниця в залежностях, необхідних для даної мети. Ні, я б не радив, щоб це було оптимально для кожного проекту, але це дає певну перспективу для управління залежністю у великих проектах.


Список літератури


Примітки

  • Це питання спочатку було задано за кілька років до введення модулів.
  • В даний час (Xcode 5.0) модулі працюють для C та ObjC, але не для C ++.

Що це означає під повною перебудовою для проекту з підтримкою модуля. Ви знаєте, що цей новий мостовий заголовок -Swift.h точно не є правильним кандидатом для .pch. Але я бачив, як люди це роблять. Тож, як ви бачите, чи хтось це робить. У нас завжди змінюється заголовок у .pch. Тож він відновлює все у файлі .pch кожного разу, коли -Swift.h регенерується. Чи згодні ви з цим? У вас більше входів?
MadNik

@MadNik Припустимо, що PCH вашого додатка включає головний заголовок бібліотеки / фреймворку, який ви активно розробляєте. Наприклад: #import "MyLib/MyLib.h". Щоразу, коли файл, включений до MyLib.hзмін, кожен вихідний файл у програмі повинен бути перекомпільований. Якщо ви використовуєте MyLib лише в одному вихідному файлі, тоді лише цей файл повинен бути перекомпільований, коли MyLib змінюється. Вірте чи ні, але сьогодні я не використовую жодних файлів PCH.
Джастін

8

Я згоден з bbum. Мій погляд на файл PCH є те , що він повинен містити в значній мірі тільки #includeабо #importзаяви. Так що якщо у вас є купа корисних макросів, високого рівня, визначити їх у чому - то начебто Common.hі #importцей файл, як це було запропоновано bbum.

Я зазвичай йду на крок далі і використовувати файл PCH в #importфайл з ім'ям XXCategories.h(де XXє клас імена префікс конвенція використовується) , який містить #importS для всіх моїх UIKit і класу Foundation категорій: NSString+XXAdditions.h, UIColor+XXAdditons.hі т.д.


Мені просто цікаво. У чому різниця між файлом .PCH між імпортом Common.h, який має різні, #importі просто імпортом #importбезпосередньо? Чи не будуть вони однаковими ?, чи це впливає на якісь результати?
Хлунг,

Наскільки мені відомо, реальної різниці немає . Це, напевно, найкраща практика. Замість того, щоб записувати купу макросів та інших речей у свій файл PCH, це повинно бути лише для #importта #include.
CIFilter

1
Різниця полягає у повторному використанні. PCH є специфічним для проекту. Common.h був би спільним для багатьох проектів. Це схоже на запитання, чому ви просто не додаєте всі свої утилітні класи у свій проект, а не створюєте підпроект, який ви можете використовувати повторно. Хоча надуманий приклад, тому що це лише проста копіювальна паста ... але копіювальна паста неслухняна.
bandejapaisa

6

створити файл заголовка "macros.h"

імпортуйте цей заголовок у Prefix.pch

У цьому macros.h поміщені всі рамки та інші важливі речі.

Якщо вас турбує продуктивність, не хвилюйтеся, подивіться, що говорить яблуко:

Заголовки та продуктивність

Якщо ви переживаєте, що включення головного файлу заголовка може спричинити здуття програми, не хвилюйтеся. Оскільки інтерфейси OS X реалізовані за допомогою фреймворків, код цих інтерфейсів знаходиться в динамічній спільній бібліотеці, а не у вашому виконуваному файлі. Крім того, лише код, який використовує ваша програма, коли-небудь завантажується в пам’ять під час виконання, тому розмір пам’яті в пам'яті залишається невеликим. Що стосується включення великої кількості файлів заголовків під час компіляції, ще раз, не хвилюйтеся. Xcode забезпечує попередньо скомпільований заголовок для прискорення часу компіляції. Компілюючи всі заголовки фреймворку одночасно, немає необхідності перекомпілювати заголовки, якщо ви не додасте новий фреймворк. Тим часом ви можете використовувати будь-який інтерфейс із включених фреймворків з незначним показником продуктивності або взагалі без нього.

також у свої макроси. 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"; });
Алехандро Іван
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.