Best practice per iOS Prefix.pch


90

Ho visto molti sviluppatori che aggiungono varie macro di convenienza al Prefix.pch dei loro progetti iOS.

Cosa consigli (o non) di aggiungere al file Prefix.pch di iOS? Che aspetto ha il tuo Prefix.pch?


Un post sul blog dettagliato sull'argomento: cimgf.com/2010/05/02/my-current-prefix-pch-file
hpique

2
Metti semplicemente le tue macro in un file di intestazione, ad esempio Macros.h, e poi importa questo file nel tuo prefix.pch.
Malloc

Sto anche affrontando lo stesso problema ... come risolvere in Xcode 6.1
Yalamandarao

Risposte:


121

Ewww… non mettere le macro in un file .pch! Un file .pch è, per definizione, un'intestazione precompilata specifica del progetto. In realtà non dovrebbe essere utilizzato al di fuori del contesto del progetto e in realtà non dovrebbe contenere nient'altro che #includes e #imports.

Se hai alcune macro e tali da condividere tra le intestazioni, inseriscile in un loro file di intestazione - Common.ho qualsiasi altra cosa - e #include quello all'inizio del .pch.


Cosa includeresti in quel Common.h?
hpique

4
Niente; Ci metterei solo i vari #defines, ecc ...
bbum

37

Per iOS e OS X moderni, le persone dovrebbero utilizzare i moduli . Questa opzione è abilitata per impostazione predefinita per i nuovi progetti e l'importazione / inclusione viene eseguita utilizzando @import.

I moduli consentono al compilatore di creare una rappresentazione intermedia del contenuto di un modulo (ad esempio gli header di un framework). Proprio come un PCH, questa rappresentazione intermedia può essere condivisa tra più traduzioni. Ma i moduli fanno un ulteriore passo avanti perché un modulo non è necessariamente specifico per la destinazione e le loro dichiarazioni non devono essere localizzate (in a *.pch). Questa rappresentazione può farti risparmiare un sacco di lavoro ridondante del compilatore.

Usando i moduli, non hai bisogno di un PCH e probabilmente dovresti semplicemente eliminarli del tutto, a favore dell'uso @importlocale alla dipendenza. In tal caso, un PCH ti evita solo di digitare inclusioni locali alle dipendenze (cosa che IMO dovresti fare comunque).

Ora, se guardiamo indietro alla domanda originale: dovresti evitare di riempire il tuo PCH con ogni sorta di cose casuali; Macro, costanti #definese ogni sorta di piccole librerie. In generale, dovresti omettere ciò che è veramente non necessario per la maggior parte dei tuoi file sorgente . Mettere ogni sorta di cose nel tuo PCH significa solo aggiungere un po 'di peso e dipendenza. Vedo che le persone inseriscono tutto ciò a cui collegano e altro ancora nel PCH. In realtà, i framework ausiliari in genere devono essere visibili solo a poche traduzioni nella maggior parte dei casi. Ad esempio "Ecco il nostro materiale per StoreKit: importiamo StoreKit solo dove deveessere visibile. In particolare, queste 3 traduzioni ". Ciò riduce i tempi di compilazione e ti aiuta a tenere traccia delle tue dipendenze, in modo da poter riutilizzare il codice più facilmente. Quindi in un progetto ObjC, di solito ti fermi alla Foundation. Se c'è molto dell'interfaccia utente, potresti prendere in considerazione l'aggiunta di UIKit o AppKit al tuo PCH. Tutto questo presuppone che tu voglia ottimizzare i tempi di compilazione. Uno dei problemi con i PCH di grandi dimensioni che includono (quasi) tutto è che la rimozione delle dipendenze non necessarie richiede molto tempo. Una volta le dipendenze del tuo progetto crescono ei tuoi tempi di compilazione aumentano, devi reagire eliminando le dipendenze non necessarie per ridurre i tempi di compilazione. Inoltre, tutto ciò che cambia spesso dovrebbe generalmente essere tenuto fuori dal tuo PCH. Una modifica richiede una ricostruzione completa. Ci sono alcune opzioni per condividere i PCH. Se utilizzi i PCH,

Per quanto riguarda quello che ho inserito nel mio PCH: ho smesso di usarli per la stragrande maggioranza degli obiettivi anni fa. Di solito non c'è abbastanza in comune per qualificarsi. Ricorda, scrivo C ++, ObjC, ObjC ++ e C - il compilatore ne emette uno per ogni lang nel tuo target. Quindi abilitarli spesso si traduceva in tempi di compilazione più lenti e I / O più elevati. In definitiva, aumentare la dipendenza non è un buon modo per combattere la dipendenza in progetti complessi. Lavorando con più lingue / dialetti, ci sono molte variazioni nelle dipendenze richieste per un dato target. No, non lo consiglierei come ottimale per ogni progetto, ma questo dà una prospettiva alla gestione delle dipendenze in progetti più grandi.


Riferimenti


Appunti

  • Questa domanda è stata inizialmente posta alcuni anni prima dell'introduzione di Modules.
  • Attualmente (Xcode 5.0), i moduli funzionano per C e ObjC, ma non per C ++.

Cosa significa ricostruzione completa per un progetto abilitato al modulo. Sai che questa nuova intestazione di bridging -Swift.h non è sicuramente un candidato giusto per un .pch. Ma ho visto persone farlo. Quindi come puoi vedere se qualcuno lo fa. Abbiamo un'intestazione in continua evoluzione in .pch. Quindi ricostruisce tutto nel file .pch ogni volta che -Swift.h viene rigenerato. Sei d'accordo con questo? Hai più input?
MadNik

@MadNik Supponiamo che il PCH della tua app includa un'intestazione principale di una libreria / framework che stai attivamente sviluppando. Ad esempio: #import "MyLib/MyLib.h". Ogni volta che un file viene incluso dalle MyLib.hmodifiche, ogni file sorgente nell'app deve essere ricompilato. Se utilizzi MyLib in un solo file sorgente, solo quel file deve essere ricompilato quando MyLib cambia. Che ci crediate o no, non sto usando alcun file PCH in questi giorni.
justin

8

Sono d'accordo con bbum. La mia opinione sul file PCH è che dovrebbe contenere praticamente solo #includeo #importdichiarazioni. Quindi, se hai un sacco di macro utili e di alto livello, definiscili in qualcosa come Common.he #importquel file, come suggerito da bbum.

Io di solito andare un ulteriore passo avanti e utilizzare il file PCH ad #importun file chiamato XXCategories.h(dove XXè la convenzione di denominazione prefisso di classe si utilizza) che contiene #imports per tutte le categorie il mio UIKit e di classe Fondazione: NSString+XXAdditions.h, UIColor+XXAdditons.h, etc.


Sono solo curioso. Nel file .PCH, qual è la differenza tra importare un Common.h che ha vari #importe importarli #importdirettamente? Non sarebbero la stessa cosa? O influisce sulle prestazioni?
Hlung

Per quanto ne so, non c'è vera differenza. È più una best practice, immagino. Invece di inserire un mucchio di macro e altre cose nel tuo file PCH, dovrebbe essere solo per #importe #include.
CIFilter

1
La differenza è la riutilizzabilità. Il PCH è specifico del progetto. Common.h sarebbe comune a molti progetti. È come chiedere perché non metti tutte le classi util nel tuo progetto invece di creare un sottoprogetto che puoi riutilizzare. Anche se un esempio artificioso, perché è solo un semplice copia incolla ... ma copia incolla è cattivo.
bandejapaisa

6

creare un file di intestazione "macros.h"

importa questa intestazione in Prefix.pch

In questo macros.h metti tutti i framework e altre cose importanti.

Se sei preoccupato per le prestazioni, non preoccuparti, guarda cosa dice Apple:

Intestazioni e prestazioni

Se sei preoccupato che l'inclusione di un file di intestazione principale possa far gonfiare il tuo programma, non preoccuparti. Poiché le interfacce OS X vengono implementate utilizzando framework, il codice per tali interfacce risiede in una libreria condivisa dinamica e non nel tuo eseguibile. Inoltre, solo il codice utilizzato dal programma viene caricato in memoria in fase di runtime, quindi anche il footprint in memoria rimane piccolo. Per quanto riguarda l'inclusione di un gran numero di file di intestazione durante la compilazione, ancora una volta, non preoccuparti. Xcode fornisce una funzione di intestazione precompilata per accelerare i tempi di compilazione. Compilando tutte le intestazioni del framework contemporaneamente, non è necessario ricompilare le intestazioni a meno che non si aggiunga un nuovo framework. Nel frattempo, puoi utilizzare qualsiasi interfaccia dai framework inclusi con poca o nessuna penalizzazione delle prestazioni.

anche nel mio macro.h metto molte costanti come:

// 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
Un altro utile qui: #define async(...) dispatch_async(dispatch_get_main_queue(), __VA_ARGS__ )... per eseguire blocchi sul thread principale:async(^{ self.someLabel.text = @":D"; });
Alejandro Iván
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.