Widziałem wielu programistów, którzy dodali różne wygodne makra do Prefix.pch swoich projektów iOS.
Co warto (a czego nie) polecać dodać do pliku iOS Prefix.pch? Jak wygląda Twój Prefix.pch?
Widziałem wielu programistów, którzy dodali różne wygodne makra do Prefix.pch swoich projektów iOS.
Co warto (a czego nie) polecać dodać do pliku iOS Prefix.pch? Jak wygląda Twój Prefix.pch?
Macros.h
, a następnie zaimportuj ten plik do pliku prefix.pch
.
Odpowiedzi:
Eee… nie umieszczaj makr w pliku .pch! Plik .pch jest z definicji prekompilowanym nagłówkiem specyficznym dla projektu. Naprawdę nie powinno się go używać poza kontekstem projektu i naprawdę nie powinno zawierać niczego poza #include
s i #import
s.
Jeśli masz jakieś makra i takie, które chcesz udostępnić między nagłówkami, umieść je we własnym pliku nagłówkowym - Common.h
lub czymkolwiek - i #include
to na początku pliku .pch.
W przypadku nowoczesnych systemów iOS i OS X ludzie powinni używać modułów . Jest to domyślnie włączone dla nowych projektów, a importowanie / włączanie odbywa się za pomocą @import
.
Moduły pozwalają kompilatorowi stworzyć pośrednią reprezentację zawartości modułu (np. Nagłówki frameworka). Podobnie jak PCH, ta reprezentacja pośrednia może być współdzielona w wielu tłumaczeniach. Ale moduły idą o krok dalej, ponieważ moduł niekoniecznie jest specyficzny dla celu, a ich deklaracje nie muszą być lokalizowane (do a *.pch
). Ta reprezentacja może zaoszczędzić mnóstwo zbędnej pracy kompilatora.
Korzystając z modułów, nie potrzebujesz PCH i prawdopodobnie powinieneś po prostu całkowicie je pozbyć - na korzyść użycia @import
lokalnego dla zależności. W takim przypadku PCH chroni cię tylko przed wpisywaniem inkluzji lokalnych w zależnościach (którą IMO i tak powinieneś robić).
Teraz, jeśli spojrzymy wstecz na pierwotne pytanie: Powinieneś unikać wypełniania PCH różnymi rodzajami przypadkowych rzeczy; Makra, stałe #defines
i wszelkiego rodzaju małe biblioteki. Generalnie powinieneś pominąć to, co naprawdę jest niepotrzebne dla większości plików źródłowych . Umieszczanie wszelkiego rodzaju rzeczy w PCH to po prostu dodawanie wagi i zależności. Widzę, że ludzie umieszczają wszystko, co łączą, a nawet więcej w PCH. W rzeczywistości ramy pomocnicze w większości przypadków muszą być widoczne tylko dla kilku tłumaczeń. Np. „Oto nasze rzeczy StoreKit - zaimportujmy StoreKit tylko tam, gdzie jest to koniecznebądź widoczny. W szczególności te 3 tłumaczenia ”. To skraca czas kompilacji i pomaga śledzić zależności, dzięki czemu można łatwiej ponownie wykorzystać kod. W projekcie ObjC zwykle zatrzymujesz się na Foundation. Jeśli jest dużo interfejsu użytkownika, możesz rozważyć dodanie UIKit lub AppKit do swojego PCH. Wszystko to przy założeniu, że chcesz zoptymalizować czas kompilacji. Jednym z problemów z dużymi PCH, które zawierają (prawie) wszystko, jest to, że usuwanie niepotrzebnych zależności jest bardzo czasochłonne. Kiedyś. Zależności twojego projektu rosną, a czas kompilacji wydłuża się, musisz walczyć, eliminując niepotrzebne zależności, aby skrócić czas kompilacji. Ponadto wszystko, co często się zmienia, powinno być generalnie wyłączone z PCH. Zmiana wymaga pełnej przebudowy. Istnieje kilka opcji udostępniania PCH. Jeśli używasz PCH,
Jeśli chodzi o to, co umieściłem w moim PCH: przestałem ich używać w większości celów lata temu. Po prostu zwykle nie ma ich wystarczająco dużo, aby się zakwalifikować. Pamiętaj, że piszę C ++, ObjC, ObjC ++ i C - kompilator emituje po jednym dla każdego języka w Twoim celu. Dlatego włączenie ich często skutkowało wolniejszymi czasami kompilacji i wyższymi I / O. Ostatecznie zwiększanie zależności nie jest dobrym sposobem walki z uzależnieniem w złożonych projektach. Pracując z wieloma językami / dialektami, istnieje wiele różnic w zależnościach wymaganych dla danego celu. Nie, nie radziłbym tego jako optymalnego dla każdego projektu, ale to daje pewną perspektywę dla zarządzania zależnościami w większych projektach.
Bibliografia
Uwagi
#import "MyLib/MyLib.h"
. Za każdym razem, gdy plik zostanie uwzględniony w MyLib.h
zmianach, każdy plik źródłowy w aplikacji musi zostać ponownie skompilowany. Jeśli używasz MyLib tylko w jednym pliku źródłowym, tylko ten plik musi zostać ponownie skompilowany, gdy zmieni się MyLib. Wierz lub nie, ale obecnie nie używam żadnych plików PCH.
Zgadzam się z bbum. Moje zdanie na temat pliku PCH jest takie, że powinien zawierać tylko #include
lub wyłącznie #import
oświadczenia. Więc jeśli masz kilka pomocnych makr wysokiego poziomu, zdefiniuj je w czymś takim jak Common.h
i #import
tym pliku, jak sugerował bbum.
Ja zwykle pójść o krok dalej i użyć pliku PCH do #import
pliku o nazwie XXCategories.h
(gdzie XX
jest klasa konwencji nazewnictwa prefiks użyć), który zawiera #import
s dla wszystkich kategorii moja UIKit i klasowych założenia: NSString+XXAdditions.h
, UIColor+XXAdditons.h
, itd.
#import
a zwykłym importowaniem tych plików #import
bezpośrednio? Czy to nie byłoby to samo? Czy ma to wpływ na wydajność?
#import
i #include
.
utwórz plik nagłówkowy „macros.h”
zaimportuj ten nagłówek do Prefix.pch
W tym macros.h umieść wszystkie frameworki i inne ważne rzeczy.
Jeśli martwisz się o wydajność, nie martw się, zobacz, co mówi Apple:
Nagłówki i wydajność
Jeśli obawiasz się, że dołączenie głównego pliku nagłówkowego może spowodować rozdęcie programu, nie martw się. Ponieważ interfejsy OS X są implementowane przy użyciu struktur, kod tych interfejsów znajduje się w dynamicznej bibliotece współdzielonej, a nie w pliku wykonywalnym. Ponadto tylko kod używany przez program jest zawsze ładowany do pamięci w czasie wykonywania, więc ślad w pamięci podobnie pozostaje mały. Jeśli chodzi o dołączanie dużej liczby plików nagłówkowych podczas kompilacji, po raz kolejny nie martw się. Xcode udostępnia funkcję prekompilowanego nagłówka, która przyspiesza czas kompilacji. Kompilując jednocześnie wszystkie nagłówki struktury, nie ma potrzeby ponownej kompilacji nagłówków, chyba że dodasz nową strukturę. W międzyczasie możesz używać dowolnego interfejsu z dołączonych frameworków z niewielkim lub żadnym spadkiem wydajności.
również w moich macros.h umieściłem wiele stałych, takich jak:
// 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__ )
... do uruchamiania bloków na głównym wątku:async(^{ self.someLabel.text = @":D"; });