Jak mogę uzyskać listę (w postaci NSArray
lub NSDictionary
) właściwości danego obiektu w Objective-C?
Wyobraź sobie następujący scenariusz: zdefiniowałem klasę nadrzędną, która po prostu rozszerza NSObject
, która przechowuje an NSString
, a BOOL
i NSData
obiekt jako właściwości. Następnie mam kilka klas, które rozszerzają tę klasę nadrzędną, dodając do każdej z nich wiele różnych właściwości.
Czy istnieje sposób, w jaki mógłbym zaimplementować metodę instancji w klasie nadrzędnej, która przechodzi przez cały obiekt i zwraca, powiedzmy, NSArray
każdą z właściwości klasy (potomnej), ponieważ nieNSStrings
ma ich w klasie nadrzędnej, więc mogę później ich użyć NSString
dla KVC?
[NSString stringWithCString:]
jest przestarzały na korzyść[NSString stringWithCString:encoding:]
.Odpowiedź @ boliva jest dobra, ale wymaga trochę więcej, aby obsługiwać prymitywy, takie jak int, long, float, double itp.
Zbudowałem go, aby dodać tę funkcjonalność.
źródło
#import <Foundation/Foundation.h>
na początku pliku .h?Odpowiedź @ orange80 ma jeden problem: w rzeczywistości nie zawsze kończy ciąg z 0. Może to prowadzić do nieoczekiwanych rezultatów, takich jak awaria podczas próby konwersji do UTF8 (z tego powodu miałem dość denerwującego crashbuga. Fajnie było go debugować ^^). Naprawiłem to, pobierając NSString z atrybutu, a następnie wywołując cStringUsingEncoding :. To działa teraz jak urok. (Działa również z ARC, przynajmniej dla mnie)
Więc to jest teraz moja wersja kodu:
źródło
Kiedy próbowałem z iOS 3.2, funkcja getPropertyType nie działa dobrze z opisem właściwości. Znalazłem przykład z dokumentacji iOS: „Przewodnik programowania w środowisku wykonawczym Objective-C: deklarowane właściwości”.
Oto poprawiony kod listy nieruchomości w iOS 3.2:
źródło
Odkryłem, że rozwiązanie bolivy działa dobrze w symulatorze, ale na urządzeniu podciąg o stałej długości powoduje problemy. Napisałem bardziej przyjazne dla Objective-C rozwiązanie tego problemu, które działa na urządzeniu. W mojej wersji konwertuję C-String atrybutów na NSString i wykonuję na nim operacje na łańcuchach, aby uzyskać podłańcuch zawierający tylko opis typu.
źródło
Ta implementacja działa zarówno z typami obiektów Objective-C, jak i prymitywami C. Jest kompatybilny z iOS 8. Ta klasa udostępnia trzy metody klas:
Zwraca słownik wszystkich widocznych właściwości obiektu, w tym właściwości wszystkich jego nadklas.
Zwraca słownik wszystkich widocznych właściwości klasy, w tym właściwości wszystkich jej nadklas.
Zwraca słownik wszystkich widocznych właściwości, które są specyficzne dla podklasy. Właściwości jego nadklas nie są uwzględnione.
Jednym z przydatnych przykładów użycia tych metod jest skopiowanie obiektu do instancji podklasy w Objective-C bez konieczności określania właściwości w metodzie kopiowania . Część tej odpowiedzi opiera się na innych odpowiedziach na to pytanie, ale zapewnia bardziej przejrzysty interfejs dla pożądanej funkcjonalności.
Nagłówek:
Realizacja:
źródło
Jeśli ktoś potrzebuje uzyskać również właściwości odziedziczone po klasach nadrzędnych (tak jak ja), oto jakaś modyfikacja w kodzie " orange80 ", aby był rekurencyjny:
źródło
Słowo „atrybuty” jest trochę rozmyte. Masz na myśli zmienne instancji, właściwości, metody, które wyglądają jak akcesory?
Odpowiedź na wszystkie trzy pytania brzmi „tak, ale nie jest to łatwe”. Objective-C Runtime API zawiera funkcje, aby otrzymać listę Ivar, listy metoda lub listę właściwości dla klasy (na przykład
class_copyPropertyList()
), a następnie odpowiednią funkcję dla każdego typu, aby uzyskać nazwę elementu na liście (na przykładproperty_getName()
).Podsumowując, może to być trochę pracy, aby to zrobić dobrze, lub przynajmniej dużo więcej, niż większość ludzi chciałaby zrobić dla czegoś, co zwykle sprowadza się do naprawdę trywialnej funkcji.
Alternatywnie, możesz po prostu napisać skrypt Ruby / Python, który po prostu czyta plik nagłówkowy i szuka wszelkich „atrybutów” klasy.
źródło
Udało mi się uzyskać odpowiedź @ orange80 dotyczącą pracy Z WŁĄCZONYM ŁUKIEM ... ... na to, czego chciałem - przynajmniej ... ale nie bez odrobiny prób i błędów. Miejmy nadzieję, że te dodatkowe informacje mogą oszczędzić komuś smutku.
Zapisz te klasy, które opisuje w swojej odpowiedzi = jako klasę, a w swoim
AppDelegate.h
(lub czymkolwiek) umieść#import PropertyUtil.h
. Następnie w twoim ...metoda (lub cokolwiek)
…
Sekretem jest rzutowanie zmiennej instancji twojej klasy ( w tym przypadku moja klasa to
Gist
, a moja instancjaGist
jestgist
), którą chcesz odpytać ... do NSObject …(id)
itd., Nie przerwie tego ... dla różnych, dziwnych , ezoteryczne powody. To da ci takie wyniki…Dla wszystkich nieskrępowanych / OCD Apple przechwalających się introspekcją ObjC „zdumiewające kulki”… Z pewnością nie ułatwiają wykonania tego prostego „spojrzenia” „na siebie”, „że tak powiem” ..
Jeśli jednak naprawdę chcesz zaszaleć… sprawdź… class-dump , który jest oszałamiająco szalonym sposobem na zajrzenie do nagłówków klas DOWOLNEGO pliku wykonywalnego itp.… Zapewnia VERBOSE spojrzenie na Twoje klasy… że ja, osobiście znaleźć naprawdę pomocne - w wielu, wielu okolicznościach. właśnie dlatego zacząłem szukać rozwiązania pytania PO. oto niektóre parametry użytkowe ... miłej zabawy!
źródło
Masz trzy magiczne zaklęcia
Poniższy fragment kodu może ci pomóc.
źródło
Używałem dostarczonej funkcji boliva, ale najwyraźniej przestała działać z iOS 7. Więc teraz zamiast statycznej const char * getPropertyType (właściwość objc_property_t) można po prostu użyć następującego:
źródło
Dla szybkich gapiów możesz uzyskać tę funkcjonalność, wykorzystując ją
Encodable
. Wytłumaczę jak:Zgodność obiektu z
Encodable
protokołemUtwórz rozszerzenie dla,
Encodable
aby zapewnićtoDictionary
funkcjonalnośćWywołaj
toDictionary
instancję obiektu i uzyskaj dostęp dokeys
właściwości.Voila! Uzyskaj dostęp do swoich nieruchomości w następujący sposób:
źródło
Te odpowiedzi są pomocne, ale wymagam od tego więcej. Wszystko, co chcę zrobić, to sprawdzić, czy typ klasy właściwości jest równy typowi istniejącego obiektu. Wszystkie powyższe kody nie są w stanie tego zrobić, ponieważ: Aby uzyskać nazwę klasy obiektu, object_getClassName () zwraca teksty takie jak te:
Ale jeśli wywołujesz getPropertyType (...) z powyższego przykładowego kodu, z 4 objc_property_t strukturami właściwości klasy zdefiniowanej w następujący sposób:
zwraca ciągi odpowiednio w następujący sposób:
Nie jest więc w stanie określić, czy obiekt NSObject może być wartością jednej właściwości tej klasy. Jak więc to zrobić?
Oto mój pełny przykładowy kod (funkcja getPropertyType (...) jest taka sama jak powyżej):
źródło