Ponieważ nie mogę utworzyć zsyntetyzowanej właściwości w kategorii w celu C, nie wiem, jak zoptymalizować następujący kod:
@interface MyClass (Variant)
@property (nonatomic, strong) NSString *test;
@end
@implementation MyClass (Variant)
@dynamic test;
- (NSString *)test {
NSString *res;
//do a lot of stuff
return res;
}
@end
Metoda testowa jest wywoływana wiele razy w czasie wykonywania i robię dużo rzeczy, aby obliczyć wynik. Zwykle używając zsyntetyzowanej właściwości, przechowuję wartość w IVar _test przy pierwszym wywołaniu metody i zwracam tę wartość IVar następnym razem. Jak mogę zoptymalizować powyższy kod?
objective-c
categories
dhrm
źródło
źródło
Odpowiedzi:
Metoda @ lorean zadziała (uwaga: odpowiedź została usunięta) , ale miałbyś tylko jedno miejsce na dane. Więc jeśli chcesz użyć tego w wielu wystąpieniach i kazać każdemu wystąpieniu obliczać odrębną wartość, nie zadziała.
Na szczęście środowisko wykonawcze Objective-C ma coś, co nazywa się obiektami powiązanymi, które mogą robić dokładnie to, czego chcesz:
źródło
@selector(test)
jako klucza, jak wyjaśniono tutaj: stackoverflow.com/questions/16020918/ ...plik h
plik .m
Podobnie jak zwykła właściwość - dostępna za pomocą notacji kropkowej
Łatwiejsza składnia
Alternatywnie możesz użyć
@selector(nameOfGetter)
zamiast tworzenia statycznego klawisza wskaźnika, jak poniżej:Więcej informacji można znaleźć pod adresem https://stackoverflow.com/a/16020927/202451
źródło
@dynamic objectTag;
.@dynamic
oznacza, że setter i getter zostaną wygenerowane gdzie indziej, ale w tym przypadku są one zaimplementowane tutaj.Podana odpowiedź działa świetnie, a moja propozycja jest tylko jej rozszerzeniem, które pozwala uniknąć pisania zbyt wielu standardowych kodów.
Aby uniknąć wielokrotnego pisania metod pobierających i ustawiających dla właściwości kategorii, ta odpowiedź wprowadza makra. Dodatkowo te makra ułatwiają korzystanie z właściwości typów pierwotnych, takich jak
int
lubBOOL
.Tradycyjne podejście bez makr
Tradycyjnie definiujesz właściwość kategorii, taką jak
Następnie musisz zaimplementować metodę pobierającą i ustawiającą, używając skojarzonego obiektu i selektora pobierania jako klucza ( patrz oryginalna odpowiedź ):
Moje sugerowane podejście
Teraz, używając makra, napiszesz zamiast tego:
Makra są zdefiniowane w następujący sposób:
Makro
CATEGORY_PROPERTY_GET_SET
dodaje metodę pobierającą i ustawiającą dla danej właściwości. Właściwości tylko do odczytu lub tylko do zapisu będą używać odpowiednio makraCATEGORY_PROPERTY_GET
iCATEGORY_PROPERTY_SET
.Trochę więcej uwagi wymagają typy prymitywne
Ponieważ typy pierwotne nie są obiektami, powyższe makra zawierają przykład użycia
unsigned int
jako typu właściwości. Czyni to poprzez zawijanie wartości całkowitej doNSNumber
obiektu. Więc jego użycie jest analogiczne do poprzedniego przykładu:W następstwie tego wzorca, można po prostu dodać więcej makr również wspierać
signed int
,BOOL
itp ...Ograniczenia
Wszystkie makra są
OBJC_ASSOCIATION_RETAIN_NONATOMIC
domyślnie używane.IDE, takie jak App Code , obecnie nie rozpoznają nazwy ustawiającego podczas refaktoryzacji nazwy właściwości. Musisz samodzielnie zmienić jego nazwę.
źródło
#import <objc/runtime.h>
w przeciwnym razie nie zapomnij dodać do kategorii .m pliku. błąd czasu kompilacji: niejawna deklaracja funkcji „objc_getAssociatedObject” jest nieprawidłowa w C99 . stackoverflow.com/questions/9408934/…Po prostu użyj biblioteki libextobjc :
plik h:
m-plik:
Więcej o @synthesizeAssociation
źródło
Testowane tylko z iOS 9 Przykład: Dodawanie właściwości UIView do UINavigationBar (Category)
UINavigationBar + Helper.h
UINavigationBar + Helper. M
źródło
Innym możliwym rozwiązaniem, być może łatwiejszym, którego nie używa,
Associated Objects
jest zadeklarowanie zmiennej w pliku implementacji kategorii w następujący sposób:Wadą tego rodzaju implementacji jest to, że obiekt nie działa jako zmienna instancji, ale raczej jako zmienna klasy. Nie można również przypisywać atrybutów właściwości (takich jak używane w obiektach powiązanych, takich jak OBJC_ASSOCIATION_RETAIN_NONATOMIC)
źródło