web-dev-qa-db-fra.com

Meilleures pratiques iOS Prefix.pch

J'ai vu de nombreux développeurs qui ajoutent diverses macros pratiques au Prefix.pch de leurs projets iOS.

Que recommandez-vous (ou non) d'ajouter au fichier iOS Prefix.pch? À quoi ressemble votre Prefix.pch?

88
hpique

Ewww… ne mettez pas de macros dans un fichier .pch! Un fichier .pch est, par définition, un en-tête précompilé spécifique au projet. Il ne devrait vraiment pas être utilisé au-delà du contexte du projet et ne devrait pas contenir autre chose que #includele sable #imports.

Si vous avez des macros et que vous souhaitez partager entre les en-têtes, alors collez-les dans leur propre fichier d'en-tête - Common.h ou autre chose - et #includethat au début du .pch.

122
bbum

Pour iOS et OS X modernes, les gens devraient utiliser Modules . Ceci est activé par défaut pour les nouveaux projets et l'importation/inclusion est effectuée à l'aide de @import.

Les modules permettent au compilateur de créer une représentation intermédiaire du contenu d'un module (par exemple les en-têtes d'un framework). Tout comme un PCH, cette représentation intermédiaire peut être partagée entre plusieurs traductions. Mais les modules vont encore plus loin car un module n'est pas nécessairement spécifique à une cible et leurs déclarations n'ont pas besoin d'être localisées (vers un *.pch). Cette représentation peut vous faire économiser une tonne de travail de compilation redondant.

En utilisant des modules, vous n'avez pas besoin d'un PCH, et vous devriez probablement les supprimer entièrement - en faveur de l'utilisation de @import local à la dépendance. Dans ce cas, un PCH ne fait que vous sauver de taper inclusions locales aux dépendances (quelle IMO vous devriez faire de toute façon).

Maintenant, si nous revenons à la question d'origine: vous devriez éviter de remplir votre PCH avec toutes sortes de choses aléatoires; Macros, constantes, #defines, et toutes sortes de petites bibliothèques. En règle générale, vous devez omettre ce qui est vraiment inutile pour la majorité de vos fichiers source . Mettre toutes sortes de choses dans votre PCH, c'est simplement ajouter un tas de poids et de dépendance. Je vois des gens mettre tout ce qu'ils lient dans PCH. En réalité, les cadres auxiliaires n'ont généralement besoin d'être visibles que par quelques traductions dans la plupart des cas. Par exemple. "Voici nos trucs StoreKit - importons StoreKit uniquement là où doit être visible. Plus précisément, ces 3 traductions". Cela réduit vos temps de génération et vous aide à garder une trace de vos dépendances, afin que vous puissiez réutiliser le code plus facilement. Donc, dans un projet ObjC, vous vous arrêtez généralement à Foundation. S'il y a beaucoup d'interface utilisateur, vous pouvez envisager d'ajouter UIKit ou AppKit à votre PCH. Tout cela en supposant que vous souhaitez optimiser les temps de construction. L'un des problèmes des gros PCH qui incluent (presque) tout est que la suppression des dépendances inutiles prend beaucoup de temps. Une fois que les dépendances de votre projet augmentent et que vos temps de construction augmentent, vous devez vous battre en éliminant les dépendances inutiles afin de réduire vos temps de construction. De plus, tout ce qui change souvent doit généralement être conservé hors de votre PCH. Un changement nécessite une reconstruction complète. Il existe quelques options pour partager les PCH. Si vous utilisez des PCH, essayez de prendre en charge le partage.

En ce qui concerne ce que j'ai mis dans mon PCH: j'ai cessé de les utiliser pour la grande majorité des cibles il y a des années. Il n'y a généralement pas assez de points communs pour se qualifier. Gardez à l'esprit, j'écris C++, ObjC, ObjC++ et C - le compilateur en émet un pour chaque langue de votre cible. Leur activation a donc souvent entraîné des temps de compilation plus lents et des E/S plus élevées. En fin de compte, l'augmentation de la dépendance n'est pas un bon moyen de lutter contre la dépendance dans les projets complexes. En travaillant avec plusieurs langues/dialectes, il existe de nombreuses variations dans les dépendances requises pour une cible donnée. Non, je ne conseillerais pas cela comme optimal pour chaque projet, mais cela donne une certaine perspective à la gestion des dépendances dans les grands projets.


Les références


Remarques

  • Cette question a été initialement posée quelques années avant l'introduction des modules.
  • Actuellement (Xcode 5.0), les modules fonctionnent pour C et ObjC, mais pas C++.
36
justin

Je suis d'accord avec bbum. Mon point de vue sur le fichier PCH est qu'il ne devrait contenir quasiment que #include ou #import déclarations. Donc, si vous avez un tas de macros de haut niveau utiles, définissez-les dans quelque chose comme Common.h et #import ce fichier, comme l'a suggéré bbum.

Je vais généralement plus loin et j'utilise le fichier PCH pour #import un fichier appelé XXCategories.h (où XX est la convention de préfixe de dénomination de classe que vous utilisez) qui contient #imports pour toutes mes catégories de classe UIKit et Foundation: NSString+XXAdditions.h, UIColor+XXAdditons.h, etc.

8
CIFilter

créer un fichier d'en-tête "macros.h"

importer cet en-tête dans Prefix.pch

Dans ce macros.h mettre tous les cadres et autres choses importantes.

Si vous êtes préoccupé par les performances, ne vous inquiétez pas, regardez ce que Apple dit:

En-têtes et performances

Si vous craignez qu’inclure un fichier d’en-tête principal puisse faire gonfler votre programme, ne vous inquiétez pas. Étant donné que les interfaces OS X sont implémentées à l'aide de frameworks, le code de ces interfaces réside dans une bibliothèque partagée dynamique et non dans votre exécutable. De plus, seul le code utilisé par votre programme est chargé en mémoire lors de l'exécution, de sorte que votre empreinte en mémoire reste également petite. Quant à l'inclusion d'un grand nombre de fichiers d'en-tête lors de la compilation, encore une fois, ne vous inquiétez pas. Xcode fournit une fonction d'en-tête précompilé pour accélérer les temps de compilation. En compilant tous les en-têtes de framework à la fois, il n'est pas nécessaire de recompiler les en-têtes sauf si vous ajoutez un nouveau framework. En attendant, vous pouvez utiliser n'importe quelle interface des frameworks inclus avec peu ou pas de pénalité de performance.

également dans mes macros.h j'ai mis beaucoup de constantes comme:

// 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];
6
Leo Cavalcante