He visto a muchos desarrolladores que agregan varias macros de conveniencia al Prefix.pch de sus proyectos de iOS.
¿Qué recomienda (o no) agregar al archivo Prefix.pch de iOS? ¿Cómo se ve su Prefix.pch?
He visto a muchos desarrolladores que agregan varias macros de conveniencia al Prefix.pch de sus proyectos de iOS.
¿Qué recomienda (o no) agregar al archivo Prefix.pch de iOS? ¿Cómo se ve su Prefix.pch?
Macros.h
, y luego importe este archivo a su prefix.pch
.
Respuestas:
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
s y #import
s.
Si tiene algunas macros y desea compartirlas entre encabezados, péguelas en un archivo de encabezado propio, Common.h
o lo #include
que sea, y eso al principio del .pch.
Para iOS y OS X modernos, la gente debería usar módulos . Esto está habilitado de forma predeterminada para nuevos proyectos, y la importación / inclusión se realiza mediante @import
.
Los módulos permiten al compilador crear una representación intermedia del contenido de un módulo (por ejemplo, los encabezados de un marco). Al igual que un PCH, esta representación intermedia se puede compartir entre varias traducciones. Pero los módulos llevan esto un paso más allá porque un módulo no es necesariamente un objetivo específico y sus declaraciones no necesitan ser localizadas (a *.pch
). Esta representación puede ahorrarle mucho trabajo de compilación redundante.
Al usar módulos, no necesita un PCH, y probablemente debería eliminarlos por completo, a favor de usar @import
local para la dependencia. En ese caso, un PCH solo le evita escribir inclusiones locales a dependencias (lo que en mi opinión debería hacer de todos modos).
Ahora, si miramos hacia atrás a la pregunta original: debe evitar llenar su PCH con todo tipo de cosas aleatorias; Macros, constantes #defines
y todo tipo de pequeñas bibliotecas. Generalmente, debe omitir lo que realmente es innecesario para la mayoría de sus archivos fuente . Poner todo tipo de cosas en su PCH es solo agregar un montón de peso y dependencia. Veo que la gente pone todo lo que enlaza y más en el PCH. En realidad, los marcos auxiliares normalmente solo necesitan ser visibles para unas pocas traducciones en la mayoría de los casos. Por ejemplo, "Aquí está nuestro material de StoreKit: importemos StoreKit solo donde debase visible. Específicamente, estas 3 traducciones ". Esto mantiene los tiempos de compilación bajos y lo 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 de ObjC, generalmente se detendrá en Foundation. Si hay mucho de UI, entonces podría considerar agregar UIKit o AppKit a su PCH. Todo esto asumiendo que desea optimizar los tiempos de compilación. Uno de los problemas con los PCH grandes que incluyen (casi) todo es que eliminar las dependencias innecesarias lleva mucho tiempo. Una vez las dependencias de su proyecto crecen y los tiempos de compilación aumentan, necesita contraatacar eliminando las dependencias innecesarias para reducir los tiempos de compilación. Además, cualquier cosa que cambie con frecuencia generalmente debe mantenerse fuera de su PCH. Un cambio requiere una reconstrucción completa. Hay algunas opciones para compartir PCH. Si usa PCH,
En cuanto a lo que puse en mi PCH: dejé de usarlos para la gran mayoría de objetivos hace años. Por lo general, no hay suficiente en común para calificar. Tenga en cuenta que escribo C ++, ObjC, ObjC ++ y C: el compilador emite uno para cada idioma de su objetivo. Por lo tanto, habilitarlos a menudo resultó en tiempos de compilación más lentos y mayores E / S. En última instancia, aumentar la dependencia no es una buena forma de luchar contra la dependencia en proyectos complejos. Al trabajar con varios idiomas / dialectos, hay mucha variación en las dependencias necesarias para un objetivo determinado. No, no lo recomendaría como óptimo para cada proyecto, pero eso le da cierta perspectiva a la gestión de la dependencia en proyectos más grandes.
Referencias
Notas
#import "MyLib/MyLib.h"
. Cada vez que un archivo incluido por MyLib.h
cambios, todos los archivos fuente de la aplicación deben volver a compilarse. Si usa MyLib en un solo archivo fuente, solo ese archivo debe volver a compilarse cuando MyLib cambie. Lo crea o no, no estoy usando ningún archivo PCH en estos días.
Estoy de acuerdo con bbum. Mi opinión sobre el archivo PCH es que debería contener prácticamente solo declaraciones #include
o #import
. Entonces, si tiene un montón de macros útiles de alto nivel , defínelas en algo como Common.h
y #import
ese archivo, como sugirió bbum.
Yo suelo ir un paso más allá y utilizar el archivo PCH a #import
un archivo llamado XXCategories.h
(donde XX
es la clase convención de nombres de prefijo que se use) que contiene #import
s para todas las categorías de clase y mi UIKit Fundación: NSString+XXAdditions.h
, UIColor+XXAdditons.h
, etc.
#import
y simplemente importarlos #import
directamente? ¿No serían iguales ?, ¿o afecta alguna actuación?
#import
y #include
.
crear un archivo de encabezado "macros.h"
importar este encabezado en Prefix.pch
En este macros.h ponemos todos los frameworks y otras cosas importantes.
Si le preocupa el rendimiento, no se preocupe, mire lo que dice Apple:
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 de OS X se implementan mediante marcos, el código de esas interfaces reside en una biblioteca compartida dinámica y no en su ejecutable. Además, solo el código utilizado por su programa se carga en la memoria en tiempo de ejecución, por lo que su huella en la memoria permanece pequeña de manera similar. En cuanto a incluir una gran cantidad de archivos de encabezado durante la compilación, una vez más, no se preocupe. Xcode proporciona una función de encabezado precompilado para acelerar los tiempos de compilación. Al compilar todos los encabezados del marco a la vez, no es necesario volver a compilar los encabezados a menos que agregue un nuevo marco. Mientras tanto, puede utilizar cualquier interfaz de los marcos incluidos con poca o ninguna penalización de rendimiento.
también en mis macros.h puse 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];
#define async(...) dispatch_async(dispatch_get_main_queue(), __VA_ARGS__ )
... para ejecutar bloques en el hilo principal:async(^{ self.someLabel.text = @":D"; });