2011-08-17 14 views
7

Ja czasem lubię organizować elementy IB w NSArray s przede wszystkim, aby pomóc mi uporządkować moje elementy. Najczęściej różne klasy obiektów tworzą z nim tę samą tablicę. Chociaż jest wygodnym sposobem organizacji, nie może wydawać się owinąć głowę wokół dlaczego jeśli mam tablicę takich jak to:dla pętli - typ obiektu nie jest brany pod uwagę?

NSArray *array = [NSArray arrayWithObjects:((UITextField *)textField), ((UISegmentedController *)segmentedController), nil]; 

Dlaczego otrzymuję „nie reaguje na przełącznik” wiadomości, kiedy umieścić for pętlę tak:

for (UITextField *text in array) { 
    [text setText:@""]; 
} 

pętla for wydaje się być przekazane obiekty, które nie są z klasy UITextField.

Jaki jest cel deklarowania klasy obiektu, jeśli wszystkie obiekty w określonej macierzy są przekazywane przez pętlę?

EDIT Tylko dla odniesienia, to jak mam posługiwaniu się nim już teraz:

for (id *object in array) { 
    if ([object isMemberOfClass:[UITextField class]]) { 
     foo(); 
    } else if ([object isMemberOfClass:[UISegmentedController class]) { 
     bar(); 
    } 
} 
+0

'id' jest już typem wskaźnika. 99,9% czasu, chcesz użyć zwykłego typu "id", a nie wskaźnika do jednego "id *". –

Odpowiedz

10

Kiedy robisz

for (UITextField *text in... 

Wskaźniki obiekt z tablicy zostały oddane do UITextField * Rodzaj - więc jeśli obiekt nie jest rzeczywiście UITextField, wszelkiego rodzaju dziwnych rzeczy może się zdarzyć, jeśli spróbujesz zadzwonić Metody UITextField.

Więc zamiast użyć typu ID (nie * potrzebne, btw):

for (id obj in array) 

następnie sprawdzić typ jak ty i wezwać odpowiednie metody. Lub filtrować tablicy dostać tylko obiekty określonego typu, a następnie przejść chociaż tego typu tylko:

for (UITextField* text in [array filteredArrayUsingPredicate:...]) 

Edit: oto jak zbudować predykaty filtru Klasa:

Is it possible to filter an NSArray by class?

+0

Obiekty nie są rzutowane na nowe typy - są to wskaźniki. Typ wskaźnika nie ma znaczenia, jeśli chodzi o wysyłanie wiadomości. Możesz wysłać '-appendString:' do obiektu za pomocą wskaźnika typu 'NSWindow *', jeśli chcesz, i będzie działało dobrze, o ile wskaźnik rzeczywiście wskaże instancję NSMutableString. (Może pojawić się ostrzeżenie kompilatora, ale zadziała.) Jeśli wskaźnik wskazuje okno, wystąpi oczywiście błąd w czasie wykonywania, chyba że podejmiesz odpowiednie kroki, aby temu zapobiec. – Caleb

+0

Masz rację, odpowiednio zmodyfikowałem swoją odpowiedź. – SVD

+0

Część wymagająca edycji to "jeśli obiekt nie jest faktycznie UITextField, mogą się zdarzyć różne dziwne rzeczy ...". Jeśli obiekt nie jest faktycznie UITextField, otrzymasz wyjątek wyjątków selektora. – Caleb

5

Co jest punktem deklarując klasę obiektu, czy wszystkie obiekty w określonej tablicy są przekazywane przez pętlę?

Nazwa klasy jest po to, aby kompilator wiedział, czego powinien się spodziewać. Dzięki temu może spróbować dowiedzieć się, jakie metody powinien wymagać wywołania i jak można traktować obiekt. To jest ten sam pomysł, co przejście w int do metody, która zajmuje float. Metoda nie zignoruje ints - zakłada, że ​​podajesz właściwy typ. Po prostu dajesz temu konstruktorowi trochę więcej kredytu, niż to się należy:

for (UITextField *text in array) 

Po prostu nie ma takiej funkcjonalności. Sposób, w jaki to robisz, jest prawidłowy.

0

Czy na pewno nie dostaniesz błędu, gdy ten kod jest kodowany? Komunikat "nie odpowiada na selektor" jest błędem środowiska wykonawczego, a nie błędem czasu kompilacji.Kompilator nie ma pojęcia, czy obiekty w tablicy implementują -setText:, ale z pewnością wystąpi błąd podczas wysyłania tej wiadomości do instancji o numerze UISegmentedControl.

Inną możliwością jest, że masz klasę o nazwie UISegmentedController, która ma metodę -setText:. Nazwa klasy implementującej wieloczęściowy widget interfejsu użytkownika wykresu słupkowego to UISegmentedControl. Tak więc kod, który wyświetlasz, nie jest prawdziwy, testowany kod lub masz klasę, o której nie wiemy.

Powiązane problemy