Jak [self.tableView reloadData] wiesz, jakie dane przeładować?

Wkurza mnie, że mój viewcontroller, który jest tableViewController, wie bez uprzedzenia, że jego właściwość, która jest NSArray lub NSDictionary, przechowuje dane, które mają być załadowane do tabeli w celu wyświetlenia.

Wydaje mi się, że powinienem wyraźnie powiedzieć coś w stylu:

[self.tableView useData:self.MyArray];

Chcę mieć więcej niż jedną tablicę wewnątrz tableViewController i przełączać się między jedną a drugą programowo.

Zauważyłem, że gdy tableViewController korzysta z kontrolera searchViewController, można to zrobić:

if (tableView == self.searchDisplayController.searchResultsTableView) {

Byłem nawet w stanie to zrobić:

self.tableView =  self.searchDisplayController.searchResultsTableView;
[self.tableView reloadData];
Ale nigdzie nie mogę znaleźć, jak ustawić siebie.tableView powrót do głównego źródła danych!
Author: Scott Pendleton, 2010-03-14

2 answers

Okej, rozumiem Twoje frustracje, ponieważ zdecydowana większość materiałów instruktażowych iPhone ' a nie zwraca wystarczającej uwagi na ogólny projekt aplikacji. Robią beeline dla interfejsu eye candy i płacić tylko wargi do sposobu, że aplikacja powinna obsługiwać dane , mimo że obsługa danych jest cały cel aplikacji w pierwszej kolejności!

[7]}materiały instruktażowe nie poświęcają wystarczająco dużo czasu na Wyjaśnienie wzorca projektowego Model-widok-kontroler, na którym cały iPhone / Cocoa API jest oparty. Masz trudności ze zrozumieniem czegokolwiek, ponieważ próbujesz wcisnąć funkcjonalność do niewłaściwych obiektów w błędne przekonanie, że widok UI jest rdzeniem programu, ponieważ materiały instruktażowe doprowadziły cię do przekonania. Pod tym błędnym zrozumieniem nic nie ma sensu, nawet dokumentacja Apple. Musisz się cofnąć i przemyśleć. To nie Funkcja widoku decyduje, jakie dane mają być wyświetlane i kiedy mają być wyświetlane. Informatyka nie jest funkcją kontrolera widoku tabeli do przechowywania, zarządzania lub przechowywania danych aplikacji. Funkcje te prawidłowo należą do obiektu modelu danych (o którym prawdopodobnie nigdy nie słyszałeś.) Masz problem, ponieważ próbujesz podzielić zadanie model danych na widok i kontroler widoku, jeśli do niego nie należą.

Najwyraźniej Twoja aplikacja nie ma nawet modelu danych, ponieważ przechowujesz dane tabeli jako właściwości kontrolera tableview. Chociaż często widzisz to w uproszczonych przykładach samouczka, jest to zły projekt, który zapadnie się pod złożonością wszelkich, ale najbardziej trywialnych aplikacji.

Zamiast tego, Twoje dane powinny być przechowywane i zarządzane w swoim własnym obiekcie niestandardowym. To jest model danych. W Twoim przypadku wygląda to tak, jakbyś miał dane rozłożone na dwie tablice, więc stworzyłbyś obiekt modelu danych coś w tym stylu:

@interface MyDataModel : NSObject {
@protected
    NSArray *arrayOne;
    NSArray *arrayTwo;
@public
    NSArray *currentlyUsedArray;

}
@property(nonatomic, retain)  NSArray *currentlyUsedArray;

-(void) switchToArrayOne;
-(void) switchToArrayTwo;
-(void) toggleUsedArray;

@end

#import "MyDataModel.h"

@interface MyDataModel ()
@property(nonatomic, retain)  NSArray *arrayOne;
@property(nonatomic, retain)  NSArray *arrayTwo;

@end


@implementation MyDataModel

- (id) init{
    if (self=[super init]) {
        self.arrayOne=//... initialize array from some source
        self.arrayTwo=//... initialize array from some source
        self.currentlyUsedArray=self.arrayOne; //whatever default you want
    }
    return self;
}

-(void) switchToArrayOne{
    self.currentlyUsedArray=self.arrayOne;
}

-(void) switchToArrayTwo{
    self.currentlyUsedArray=self.arrayTwo;
}

- (void) toggleUsedArray{
    if (self.currentlyUsedArray==self.arrayOne) {
        self.currentlyUsedArray=self.arrayTwo;
    }else {
        self.currentlyUsedArray=self.arrayOne;
    }
}

(zauważ, że rzeczywiste dane są zamknięte i że inne obiekty mogą uzyskać dostęp tylko do currentlyUsedArray. Dane model decyduje, które dane podać na podstawie wewnętrznego stanu danych.)

Ten obiekt modelu danych powinien znajdować się w powszechnie dostępnej lokalizacji. Najlepszą metodą jest uczynienie go singletonem, ale szybką i brudną metodą jest zaparkowanie go jako atrybutu delegata aplikacji.

Więc w kontrolerze tableview będziesz miał właściwość:

MyDataModel *theDataModel;
@property (nonatomic, retain) MyDataModel *theDataModel;

Następnie w realizacji

@synthesize theDataModel;

-(MyDataModel *) theDataModel; {
    if (theDataModel; !=nil) {
        return theDataModel; ;
    }
    id appDelegate=[[UIApplication sharedApplication] delegate];
    self.theDataModel=appDelegate.theDataModelProperty;
    return theDataModel;
}

Następnie w metodzie tableview datasource:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    ...
    cell.textLabel.text=[self.theDataModel.currentlyUsedArray objectAtIndex:indexPath.row];
    return cell;
}

Jeśli jakieś zdarzenie w dowolnym miejscu w aplikacji wymaga przełączania tablic, wystarczy wywołać obiekt modelu danych z delegata aplikacji i wysłać mu odpowiednią wiadomość switch array.

id appDelegate=[[UIApplication sharedApplication] delegate];
[appDelegate.theDataModelProperty toggleUsedArray];

Teraz wszystkie kolejne operacje na danych, czy to w tym konkretnym widoku tabeli, czy w innym zupełnie niezwiązanym widoku, będą używać danych z odpowiedniej tablicy.

Po co tyle kłopotów? To sprawia, że aplikacja jest modułowa. Możesz łatwo dodać różne widoki, z których każdy wyświetla dane w inny sposób bez konieczności przepisywania zarządzania danymi za każdym razem. Za pomocą modelu danych można zarządzać danymi, które będą wyświetlane w tabeli, w widoku sieci Web lub w wierszu poleceń. Możesz nawet łatwo przenieść model danych do zupełnie innej aplikacji. [7]}ta modułowość znacznie ułatwia zarządzanie dużymi złożonymi aplikacjami. Masz tylko jeden obiekt, który manipuluje i kontroluje dane. Nie musisz się martwić, że jakiś drobny błąd w niektórych rzadko użyty segment kodu spowoduje kosz całej aplikacji. Możesz łatwo podłączyć widoki lub łatwo je usunąć bez łamania aplikacji. To oczywiście trywialny przykład, ale pokazuje dobrą praktykę.

Możesz jednak zapytać, Jak to rozwiązuje problem tableview wiedząc, jakie dane załadować i kiedy je załadować? Proste, Nie. zadaniem tableview nie jest wiedzieć, jakie dane załadować lub kiedy załadować. Model danych obsługuje kontroler what-data i tableview poradzi sobie z "kiedy". (Możesz nawet mieć powiadomienia o problemach z modelem danych, gdy jest on aktualizowany np. dla adresu url. następnie kontroler widoku może zarejestrować się do powiadomienia i wywołać reloadData za każdym razem, gdy model danych ulegnie zmianie.)

Poprzez bezwzględne dzielenie i Hermetyzowanie funkcjonalności w MVC, tworzysz złożone aplikacje z prostych komponentów wielokrotnego użytku, które są łatwe w utrzymaniu i debugowaniu.

To jest naprawdę złe większość materiałów instruktażowych tylko zapłacić Lipa do tego całkowicie krytyczna koncepcja.

 41
Author: TechZen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-15 10:42:11

Kontroler widoku tabeli nic nie" wie bez wiedzy " - nie ma z natury właściwości, jak wspominasz, że dane pochodzą. Dostarczasz te dane, po jednej komórce na raz, zazwyczaj w podklasie kontrolera widoku.

Zazwyczaj obiekt kontrolera widoku tabeli jest zarówno delegatem widoku tabeli, jak i delegatem źródła danych widoku tabeli. Z the Apple docs:

Obiekt UITableView musi mieć delegat i źródło danych. Po projekt Model-widok-kontroler wzór, źródło danych pośredniczy pomiędzy modelem danych aplikacji (czyli jego obiektów modelowych) oraz widok tabeli; delegat, z drugiej ręka, zarządza wyglądem i zachowanie widoku tabeli. Dane źródło i delegat są często (ale niekoniecznie) ten sam przedmiot, a ten obiekt jest często zwyczaj podklasa UITableViewController.

Widok tabeli nie przyjmuje tablicy lub słownik i wyciągnij z niego dane; pyta cię w źródle danych, jak powinna wyglądać każda komórka. Wystarczy zaimplementować tę metodę:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

I zwróć zawartość w komórce, którą chcesz dla wiersza, o który cię pytają. Możesz tam umieścić logikę, aby mieszać/dopasowywać / pobierać dane z dowolnego miejsca.

Czy Twoje zamieszanie może wynikać z zupy przykładowego kodu, który nie jest jasny co się dzieje? Polecam budowanie widoku tabeli od podstaw, aby zobaczyć, jak to działa-- łatwo to zrobić, dodając nową klasę do projektu, możesz wybrać podklasę UITableViewController z wnętrza Xcode w kreatorze "nowy". To będzie prepopulate .m plik ze wszystkimi odpowiednimi pustymi metodami, w tym powyższymi.


EDIT: nie zmieniaj widoku tabeli, który posiada kontroler widoku podczas wyszukiwania. Pomyliłeś referencję do instancji o nazwie "tableView", która jest własnością kontrolera widoku, z argumentem do metody delegata tableView:cellForRowAtIndexPath:, która właśnie otrzymuje przekazałem ci który widok tabeli prosi o komórkę. Gdy wyszukiwanie jest ustawione w normalny sposób z tym samym kontrolerem viewcontroller, który jest delegatem zarówno dla tabeli domyślnej/zawartości, jak i wyników wyszukiwania, możesz zostać wywołany z jednym z nich. zobacz tutaj, aby uzyskać dokumenty na ten .

 2
Author: Ben Zotto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-14 15:11:52