Mejores prácticas de iOS Prefix.pch
objective-c xcode (4)
He visto muchos desarrolladores que agregan varias macros de conveniencia al Prefix.pch de sus proyectos de iOS.
¿Qué (o no) recomienda agregar al archivo iOS Prefix.pch? ¿Cómo se ve tu Prefix.pch?
Estoy de acuerdo con bbum. Mi opinión sobre el archivo PCH es que debería contener prácticamente solo sentencias #include
o #import
. Por lo tanto, si tiene un montón de macros útiles de alto nivel, Common.h
en algo como Common.h
ese archivo, como sugirió bbum.
Normalmente voy un paso más allá y uso el archivo PCH para #import
un archivo llamado XXCategories.h
(donde XX
es la convención de prefijo de nomenclatura de clases que usa) que contiene # #import
para todas mis categorías de clase UIKit y Foundation: NSString+XXAdditions.h
, UIColor+XXAdditons.h
, etc.
Ewww ... no pongas macros en un archivo .pch! Un archivo .pch es, por definición, un encabezado precompilado específico del proyecto. Realmente no debería usarse más allá del contexto del proyecto y realmente no debería contener nada más que #include
y #import
s.
Si tiene algunas macros y desea compartirlas entre las cabeceras, Common.h
en un archivo de encabezado propio - Common.h
o lo que sea - y #include
eso al comienzo de .pch.
Para iOS y OS X modernos, las personas deberían usar Módulos . Esto está habilitado por defecto para nuevos proyectos, y la importación / inclusión se lleva a cabo usando @import
.
Los módulos permiten al compilador crear una representación intermedia de los contenidos de un módulo (por ejemplo, los encabezados de un marco). Al igual que una PCH, esta representación intermedia puede compartirse a través de múltiples traducciones. Pero los módulos dan un paso más allá porque un módulo no es necesariamente específico de un objetivo, y sus declaraciones no necesitan ser localizadas (a *.pch
). Esta representación puede ahorrarle una tonelada de trabajo de compilador redundante.
Al usar módulos, no necesita una PCH, y probablemente debería deshacerse de ellos por completo, a favor de usar @import
local para la dependencia. En ese caso, un PCH solo lo está salvando de tipear inclusiones locales a dependencias (qué IMO debería estar haciendo de todos modos).
Ahora, si miramos hacia atrás a la pregunta original: debe evitar llenar su PCH con todo tipo de cosas al azar; Macros, constantes, #defines
y todo tipo de pequeñas bibliotecas. En general, debe omitir lo que realmente es innecesario para la mayoría de sus archivos fuente . Poner todo tipo de cosas en su PCH es simplemente agregar un montón de peso y dependencia. Veo que las personas ponen todo lo que enlazan y más en el PCH. En realidad, los marcos auxiliares normalmente solo deben ser visibles para algunas traducciones en la mayoría de los casos. Por ejemplo, "Aquí está nuestro material de StoreKit: vamos a importar StoreKit solo donde debe estar visible. Específicamente, estas 3 traducciones". Esto mantiene sus tiempos de compilación bajos y le ayuda a realizar un seguimiento de sus dependencias para que pueda reutilizar el código más fácilmente. Por lo tanto, en un proyecto ObjC, generalmente se detendría en Foundation. Si hay una gran cantidad de UI, entonces podría considerar agregar UIKit o AppKit a su PCH. Todo esto es asumiendo que desea optimizar los tiempos de construcción. Uno de los problemas con PCH grandes que incluyen (casi) todo es que la eliminación de dependencias innecesarias consume mucho tiempo. Una vez que las dependencias de su proyecto crecen y los tiempos de construcción aumentan, debe luchar contra la eliminación de dependencias innecesarias para reducir sus tiempos de construcción. Además, cualquier cosa que cambie a menudo debe mantenerse fuera de su PCH. Un cambio requiere una reconstrucción completa. Hay algunas opciones para compartir PCH. Si usa PCH, apunte a compartir.
En cuanto a lo que puse en mi PCH: dejé de usarlos para la gran mayoría de los objetivos hace años. Simplemente no hay suficiente en común para calificar. Tenga en cuenta que escribo C ++, ObjC, ObjC ++ y C, el compilador emite uno por cada idioma en su destino. Por lo tanto, habilitarlos a menudo daba como resultado tiempos de compilación más lentos y una mayor E / S. En última instancia, aumentar la dependencia no es una buena forma de luchar contra la dependencia en proyectos complejos. Trabajando con múltiples idiomas / dialectos, hay mucha variación en las dependencias requeridas para un objetivo dado. No, no aconsejaría eso como óptimo para cada proyecto, pero eso da una perspectiva de la gestión de la dependencia en proyectos más grandes.
Referencias
Notas
- Esta pregunta fue hecha originalmente unos años antes de la introducción de los Módulos.
- Actualmente (Xcode 5.0), los módulos funcionan para C y ObjC, pero no para C ++.
crea un archivo de encabezado "macros.h"
importar este encabezado a Prefix.pch
En este macros.h pongo todos los marcos y otras cosas importantes.
Si te preocupa el rendimiento, no te preocupes, mira lo que dice la manzana:
Encabezados y rendimiento
Si le preocupa que incluir un archivo de encabezado maestro pueda hacer que su programa se hinche, no se preocupe. Debido a que las interfaces OS X se implementan usando marcos, el código para esas interfaces reside en una biblioteca compartida dinámica y no en su ejecutable. Además, solo el código utilizado por el programa siempre se carga en la memoria en tiempo de ejecución, por lo que su huella en la memoria también se mantiene pequeña. En cuanto a incluir una gran cantidad de archivos de encabezado durante la compilación, una vez más, no se preocupe. Xcode proporciona un recurso de encabezado precompilado para acelerar los tiempos de compilación. Al compilar todos los encabezados de marcos a la vez, no hay necesidad de volver a compilar los encabezados a menos que agregue un nuevo marco. Mientras tanto, puede usar cualquier interfaz de los marcos incluidos con poca o ninguna penalización de rendimiento.
también en mis macros.h pongo muchas constantes como:
// 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];