Я видел много разработчиков, которые добавляли различные удобные макросы в Prefix.pch своих проектов iOS.
Что вы рекомендуете (или нет) добавлять в файл iOS Prefix.pch? Как выглядит ваш Prefix.pch?
Я видел много разработчиков, которые добавляли различные удобные макросы в Prefix.pch своих проектов iOS.
Что вы рекомендуете (или нет) добавлять в файл iOS Prefix.pch? Как выглядит ваш Prefix.pch?
Macros.h
, в файл заголовка , а затем импортируйте этот файл в свой prefix.pch
.
Ответы:
Фуу… не помещайте макросы в файл .pch! Файл .pch по определению представляет собой предварительно скомпилированный заголовок конкретного проекта. Его действительно не следует использовать вне контекста проекта, и он действительно не должен содержать ничего, кроме #include
s и#import
s.
Если у вас есть макросы и такие, которые вы хотите использовать в заголовках, вставьте их в отдельный файл заголовка - Common.h
или что-то еще - и #include
это в начале .pch.
Для современных iOS и OS X люди должны использовать модули . По умолчанию это включено для новых проектов, а импорт / включение выполняется с использованием @import
.
Модули позволяют компилятору создавать промежуточное представление содержимого модуля (например, заголовки фреймворка). Подобно PCH, это промежуточное представление может использоваться в нескольких переводах. Но модули делают еще один шаг вперед, потому что модуль не обязательно является целевым, и их объявления не нужно локализовать (в a *.pch
). Это представление может сэкономить массу лишней работы компилятора.
Используя модули, вам не нужен PCH, и вам, вероятно, следует просто полностью отказаться от них - в пользу использования @import
local для зависимости. В этом случае PCH только спасает вас от ввода локальных включений для зависимостей (что IMO вы все равно должны делать).
Теперь, если мы вернемся к исходному вопросу: вам следует избегать заполнения вашего PCH всевозможными случайными вещами; Макросы, константы #defines
и всевозможные маленькие библиотеки. Как правило, вы должны опускать то, что действительно не нужно для большинства ваших исходных файлов . Размещение всевозможных вещей в вашем PCH просто добавляет кучу веса и зависимости. Я вижу, как люди помещают все, на что они ссылаются, и многое другое в PCH. На самом деле, в большинстве случаев вспомогательные фреймворки должны быть видимы только для нескольких переводов. Например: «Вот наш материал StoreKit - давайте импортируем StoreKit только там, где он долженбыть видимым. В частности, эти 3 перевода ". Это сокращает время сборки и помогает отслеживать ваши зависимости, чтобы вам было легче повторно использовать код. Так что в проекте ObjC вы обычно останавливаетесь на Foundation. Если их много пользовательского интерфейса, то вы можете рассмотреть возможность добавления UIKit или AppKit на свой PCH. Все это предполагает, что вы хотите оптимизировать время сборки. Одна из проблем с большими PCH, которые включают (почти) все, заключается в том, что удаление ненужных зависимостей занимает очень много времени. зависимости вашего проекта растут, и время сборки увеличивается, вам нужно сопротивляться, устраняя ненужные зависимости, чтобы сократить время сборки. Кроме того, все, что часто изменяется, обычно следует держать за пределами вашего PCH. Для изменения требуется полная перестройка. Есть несколько вариантов совместного использования PCH. Если вы используете PCH,
Что касается того, что я вложил в свой PCH: я перестал использовать их для подавляющего большинства целей много лет назад. Просто обычно не хватает общего, чтобы квалифицироваться. Имейте в виду, что я пишу C ++, ObjC, ObjC ++ и C - компилятор выдает по одному для каждого языка вашей цели. Таким образом, их включение часто приводило к более медленному времени компиляции и увеличению количества операций ввода-вывода. В конечном счете, увеличение зависимости - не лучший способ бороться с зависимостью в сложных проектах. При работе с несколькими языками / диалектами существуют большие различия в зависимостях, необходимых для данной цели. Нет, я бы не советовал это оптимизировать для каждого проекта, но это дает некоторую перспективу управлению зависимостями в более крупных проектах.
Рекомендации
Ноты
#import "MyLib/MyLib.h"
. MyLib.h
Каждый раз, когда файл включается изменениями, каждый исходный файл в приложении необходимо перекомпилировать. Если вы используете MyLib только в одном исходном файле, то при изменении MyLib необходимо перекомпилировать только этот файл. Хотите верьте, хотите нет, но в наши дни я не использую файлы PCH.
Я согласен с bbum. Я считаю, что файл PCH должен содержать в основном только операторы #include
или #import
. Так что, если у вас есть набор полезных макросов высокого уровня, определите их в чем-то вроде Common.h
и #import
этого файла, как предлагает bbum.
Я обычно иду на шаг дальше и использовать файл PCH в #import
файл с именем XXCategories.h
(где XX
есть класс имена префикс конвенция используется) , который содержит #import
S для всех моих UIKit и класса Foundation категорий: NSString+XXAdditions.h
, UIColor+XXAdditons.h
и т.д.
#import
и просто импортировать те #import
напрямую? Разве это не то же самое? Или это влияет на производительность?
#import
и #include
.
создать файл заголовка "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];
#define async(...) dispatch_async(dispatch_get_main_queue(), __VA_ARGS__ )
... для запуска блоков в основном потоке:async(^{ self.someLabel.text = @":D"; });