Quelqu'un peut-il expliquer MVC en termes de UItableview lors de l'obtention de données pour la table à partir d'Internet?

Quelqu'un peut-il m'expliquer comment MVC fonctionne quand il s'agit de UITableView en particulier lors de l'obtention de données à partir d'Internet.

Je voudrais exactement savoir quel est le model, la vue et le controller quand il s'agit d'un UItableview

J'ai écrit le code ViewController suivant qui source datatables d'Internet et l'affiche sur une table en utilisant AFNetworking framework.

Pourriez-vous s'il vous plaît me dire comment changer cela et le séparer en model, vue et controller. J'ai également écrit un cours de rafraîchissement, que je suppose être une partie du model. Pourriez-vous me dire exactement comment je fais des changements et en faire une partie du model.

EDIT: Les réponses ci-dessous m'aident à comprendre le concept théoriquement. Quelqu'un pourrait-il m'aider à changer le code en conséquence (en écrivant un nouveau cours sur comment appeler le tableau pour cette class et remplir la table parce que j'utilise un parsingur json). Je voudrais l'impliquer. Et pas seulement le comprendre théoriquement.

#import "ViewController.h" #import "AFNetworking.h" @implementation ViewController @synthesize tableView = _tableView, activityIndicatorView = _activityIndicatorView, movies = _movies; - (void)viewDidLoad { [super viewDidLoad]; // Setting Up Table View self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0.0, 0.0, self.view.bounds.size.width, self.view.bounds.size.height) style:UITableViewStylePlain]; self.tableView.dataSource = self; self.tableView.delegate = self; self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; self.tableView.hidden = YES; [self.view addSubview:self.tableView]; // Setting Up Activity Indicator View self.activityIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; self.activityIndicatorView.hidesWhenStopped = YES; self.activityIndicatorView.center = self.view.center; [self.view addSubview:self.activityIndicatorView]; [self.activityIndicatorView startAnimating]; // Initializing Data Source self.movies = [[NSArray alloc] init]; NSURL *url = [[NSURL alloc] initWithSsortingng:@"http://itunes.apple.com/search?term=rocky&country=us&entity=movie"]; NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url]; UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init]; [refreshControl addTarget:self action:@selector(refresh:) forControlEvents:UIControlEventValueChanged]; [self.tableView addSubview:refreshControl]; [refreshControl endRefreshing]; AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) { self.movies = [JSON objectForKey:@"results"]; [self.activityIndicatorView stopAnimating]; [self.tableView setHidden:NO]; [self.tableView reloadData]; } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) { NSLog(@"Request Failed with Error: %@, %@", error, error.userInfo); }]; [operation start]; } - (void)refresh:(UIRefreshControl *)sender { NSURL *url = [[NSURL alloc] initWithSsortingng:@"http://itunes.apple.com/search?term=rambo&country=us&entity=movie"]; NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url]; AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) { self.movies = [JSON objectForKey:@"results"]; [self.activityIndicatorView stopAnimating]; [self.tableView setHidden:NO]; [self.tableView reloadData]; } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) { NSLog(@"Request Failed with Error: %@, %@", error, error.userInfo); }]; [operation start]; [sender endRefreshing]; } - (void)viewDidUnload { [super viewDidUnload]; } - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { return YES; } // Table View Data Source Methods - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { if (self.movies && self.movies.count) { return self.movies.count; } else { return 0; } } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSSsortingng *cellID = @"Cell Identifier"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID]; if (!cell) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellID]; } NSDictionary *movie = [self.movies objectAtIndex:indexPath.row]; cell.textLabel.text = [movie objectForKey:@"trackName"]; cell.detailTextLabel.text = [movie objectForKey:@"artistName"]; NSURL *url = [[NSURL alloc] initWithSsortingng:[movie objectForKey:@"artworkUrl100"]]; [cell.imageView setImageWithURL:url placeholderImage:[UIImage imageNamed:@"placeholder"]]; return cell; } @end 

C'est une question assez importante que vous posez. Mais laissez-moi répondre en le rendant aussi simple que possible.

  • Modèle – votre source de données; en fin de count, ce sont vos données de service Web
  • Le controller doit être le propriétaire de la vue de table et sert de médiateur pour définir les propriétés de votre vue et réagir aux events de la vue et apporter des modifications, au besoin, au model.
  • Vue (s) – une combinaison de vos cellules de vue de table et de table

Il existe de nombreuses methods de coordination entre vos données Web et votre vue de table, mais je suggérerais de refactoriser vos appels de service Web dans une class de magasin distincte – disons iTunesStore – que cette class soit responsable de faire les appels au service. et en définissant un tableau interne avec les résultats, il devrait également être capable de renvoyer un nombre de lignes ainsi qu'un élément spécifique pour un index de ligne donné.

Vous avez ensuite cette class répondre aux appels pour les methods déléguées de vue de table requirejses. D'autres choses à prendre en count, font que cette autre class soit un singleton, qu'elle soit conforme au protocole UITableviewDatasource lui-même et qu'elle l'affecte en tant que source de données des vues de table.

Comme je l'ai dit, une grande question avec beaucoup d'options pour vous, mais je vous ai donné quelques choses à considérer en termes d'où aller ensuite.

METTRE À JOUR
J'ajoute quelques exemples de code pour aider à clarifier. Au départ, je tiens à préciser que je ne fournirai pas la solution totale, car cela exigerait que je suppose trop de solutions réelles – et parce qu'il y a plusieurs façons de travailler avec AFNetworking , services web, etc …. et je ne veux pas être suivi de descendre ce trou de lapin. (Tels que la caching des données sur le client, les tâches en arrière-plan et GCD, etc …) Juste vous montrant comment câbler les bases – mais vous voulez certainement apprendre à utiliser AFNetworking sur une tâche de fond, se pencher sur Core Data ou NSCoding pour la caching, et quelques autres sujets pour faire ce genre de chose correctement.

Il suffit de dire que dans une bonne solution:
– Vous ne voulez pas appeler votre service Web de manière synchrone
– Vous ne voulez pas non plus requestr à nouveau les mêmes données à chaque fois, c'est-à-dire ne pas download à nouveau le même logging à partir du service, à less qu'il ne soit modifié
– Je ne montre pas comment faire ces choses ici parce que cela dépasse le cadre; regarder une recommandation de livre ci-dessous ainsi que ce lien pour avoir une idée sur ces sujets Ray Wenderlich – synchroniser datatables de base avec un service web

Pour votre code de services de données, je créerais une class 'magasin'. (Faites-vous une faveur et obtenez le livre Big Nerd Ranch iOS si vous ne l'avez pas déjà.
Programmation iOS 4ème édition

Prenez le code suivant avec un grain de sel – pour des raisons que je ne peux pas entrer je ne suis pas capable de le faire depuis mon Mac (sur une machine Win) et je ne suis pas capable de copyr ou même m'envoyer le code. .. donc je fais tout dans l'éditeur StackOverflow …

Mon contrat iTunesStore (file d'en-tête) ressemblerait à ceci:

 // iTunesStore.h #import <Foundation/Foundation.h> @interface iTunesStore : NSObject - (NSUInteger)recordCount; - (NSDictionary*)recordAtIndex:(NSUInteger)index; // could be a more specialized record class + (instancetype)sharedStore; // singleton @end 

… et la mise en œuvre ressemblerait à quelque chose comme:

 // iTunesStore.m #import "iTunesStore.h" // class extension @interface iTunesStore() @property (nonatomic, strong) NSArray* records; @end @implementation iTunesStore -(id)init { self = [super init]; if(self) { // DO NOT DO IT THIS WAY IN PRODUCTION // ONLY FOR DIDACTIC PURPOSES - Read my other comments above [self loadRecords]; } return self; } - (NSUInteger)recordCount { return [self.records count]; } - (NSDictionary*)recordAtIndex:(NSUInteger)index { NSDictionary* record = self.records[index]; } -(void)loadRecords { // simulate loading records from service synchronously (ouch!) // in production this should use GCD or NSOperationQue to // load records asynchrononusly NSInteger recordCount = 10; NSMutableArray* tempRecords = [NSMutableArray arrayWithCapacity:recordCount]; // load some dummy records for(NSInteger index = 0; index < recordCount; index++) { NSDictionary* record = @{@"id": @(index), @"title":[NSSsortingng ssortingngWithFormat:@"record %d", index]}; [tempRecords addObject:record]; } self.records = [tempRecords copy]; } // create singleton instance + (instancetype)sharedStore { static dispatch_once_t onceToken; static id _instance; dispatch_once(&onceToken, ^{ _instance = [[[self class] alloc] init]; }); return _instance; } @end 

J'ai maintenant un singleton d'object 'store' que je peux utiliser pour get des loggings, returnner un logging donné et aussi me dire un nombre d'loggings. Maintenant, je peux déplacer une grande partie de la logique à partir du viewcontroller.

Maintenant, je n'ai pas besoin de le faire dans votre méthode VC viewDidLoad. Idéalement, vous devriez avoir une méthode async dans votre object magasin pour get des loggings et un bloc pour vous callbacker une fois que les loggings sont chargés. A l'intérieur du bloc, vous rechargez les loggings. La signature pour quelque chose comme ça pourrait ressembler à:

 [[iTunesStore sharedStore] loadRecordsWithCompletion:^(NSError* error){ ... if no error assume load records succeeded ... ensure we are on the correct thread [self.tableView reloadData]; // will cause table to reload cells }]; 

Vos methods de source de données de controller de vue ressemblent maintenant à:

  - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection(NSInteger)section { [[iTunesStore sharedStore] recordCount]; } 

Inside cellForRowAtIndexPath – J'appelle aussi mon object store pour get le bon logging

  - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { // ... get cell // ... get record NSDictionary* record = [[iTunesStore sharedStore] recordAtIndex:indexPath.row]; // ... configure cell] return cell; } 

C'est l'essentiel. D'autres choses à faire, comme indiqué ci-dessus seraient:

  • ITunesStore implémente UITableViewDataSource, puis gère directement les methods de la source de données tableview. Si vous faites cela, vous ne voulez pas que iTunesStore soit un singleton. Et vous définissez une instance d'iTunesStore en tant que délégué de la table, plutôt que viewcontroller. Il y a des avantages et des inconvénients à une telle approche.
  • Je n'ai pas montré de réel comportement asynchronous ou de caching que cette application réclame
  • Cela montre comment retirer certaines de vos responsabilités de model et séparer certaines des préoccupations de source de données de tableview.

J'espère que cela vous aidera à vous faire une idée des différentes directions que vous pourriez explorer. Codage heureux!

En termes de UITableViewController, tous les rôles Model, View et Controller (MVC) sont généralement lus par votre UITableViewController lui-même. C'est le cas de votre code aussi.

  1. Comme model – Il fournit des données à votre vue de table.
  2. En tant que controller – Il contrôle l'aspect et la convivialité de la table comme le nombre de lignes, de sections, la hauteur et la largeur, etc., fournit des données du model à la vue de table
  3. As View – Sa propriété view contient l'UITableView

Maintenant, pour adopter une approche différente, Model pourrait être séparé de votre class de controller. Pour cela avoir une sous-class de NSObject et avoir son état qui pourrait être utilisé par le controller.

J'espère que ça a du sens pour toi.