从互联网上获取表格数据时,有人可以用UItableview解释MVC吗?

use*_*880 9 model-view-controller objective-c uitableview ios

任何人都可以向我解释一下,当谈到UITableView时,MVC是如何工作的,尤其是从互联网上获取数据时.

我想知道UItableview的模型,视图和控制器是什么

我编写了以下ViewController代码,该代码从Internet获取数据并使用AFNetworking框架将其显示在表中.

您能告诉我如何更改它并将其分为模型,视图和控制器.我还写了一个刷新类,我猜这是模型的一部分.你能告诉我我是如何做出改变并使其成为模型的一部分.

编辑:以下答案帮助我理解理论上的概念,有人可以帮助我相应地更改代码(通过编写一个关于如何调用数组到这个类并填充表的新类,因为我使用的是json解析器).我想实现它.而不只是从理论上理解它.

#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] initWithString:@"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] initWithString:@"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 NSString *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] initWithString:[movie objectForKey:@"artworkUrl100"]];
    [cell.imageView setImageWithURL:url placeholderImage:[UIImage imageNamed:@"placeholder"]];

    return cell;
}

@end
Run Code Online (Sandbox Code Playgroud)

Bla*_*nny 9

这是你要问的一个非常大的问题.但让我回答一下尽可能简单.

  • 模型 - 您的数据源; 最终这是你的网络服务数据
  • 控制器应该是拥有表视图并调整视图中的设置属性并对视图中的事件做出反应并根据需要对模型进行更改的事物.
  • 视图 - 表视图和表视图单元的组合

有很多方法可以协调您的Web数据和表视图,但我可能会建议将您的Web服务调用重构为一个单独的商店类 - 比如iTunesStore - 让该类负责调用服务并使用结果设置内部数组,它还应该能够返回行计数以及给定行索引的特定项.

然后,您可以让此类响应所需的表视图委托方法的调用.要考虑的其他事项,使其他类成为单例,使其符合UITableviewDatasource协议本身并将其指定为表视图的数据源.

就像我说的那样,一个很大的问题,有很多选择,但我已经给你一些事情要考虑下一步去哪里.

更新
我正在添加一些代码示例以帮助澄清.首先,我想明确表示我不打算提供整体解决方案,因为这样做需要我在必要的实际解决方案上假设太多 - 并且因为有几种不同的方法可以使用AFNetworking ,网络服务等....而且我不想被追踪到那个兔子洞.(例如在客户端上缓存数据,后台任务和GCD等等)只是向您展示如何连接基础知识 - 但您肯定想学习如何在后台任务中使用AFNetworking,查看核心数据或者用于缓存的NSCoding,以及其他一些正确执行此类操作的主题.

可以说,在适当的解决方案中:
- 您不希望同步调用您的Web服务
- 您也不希望每次都重新请求相同的数据 - 即不要重新下载相同的数据从服务中记录,除非它改变了
- 我没有在这里展示如何做这些事情,因为它超出了范围; 查看以下书籍推荐以及此链接以了解这些主题Ray Wenderlich - 使用Web服务同步Core Data

对于您的数据服务代码,我会创建一个"商店"类.(帮自己一个忙,如果你还没有它,请购买Big Nerd Ranch iOS书
.iOS编程第4版

以下是代码中的一小部分 - 由于我无法进入的原因,我无法通过我的Mac(在Win机器上)执行此操作,而且我也无法复制甚至通过电子邮件发送自己的代码. ..所以我在StackOverflow编辑器中做了所有...

我的iTunesStore合同(头文件)看起来像:

// 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
Run Code Online (Sandbox Code Playgroud)

......并且实现看起来像:

// 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":[NSString stringWithFormat:@"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
Run Code Online (Sandbox Code Playgroud)

我现在有一个'store'对象单例我可以用来获取记录,返回给定记录并告诉我记录计数.现在我可以从viewcontroller中移动很多逻辑.

现在我不需要在VC viewDidLoad方法中执行此操作.理想情况下,您将在商店对象中使用异步方法来获取记录,并在加载记录后使用块来回调您.在块中,您重新加载记录.像'可能'这样的东西的签名:

[[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
}];
Run Code Online (Sandbox Code Playgroud)

您的视图控制器数据源方法现在看起来像:

 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection(NSInteger)section {
      [[iTunesStore sharedStore] recordCount];
  }
Run Code Online (Sandbox Code Playgroud)

在cellForRowAtIndexPath里面 - 我也调用我的商店对象来获取正确的记录

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

  // ... get cell
  // ... get record
  NSDictionary* record = [[iTunesStore sharedStore] recordAtIndex:indexPath.row];

  // ... configure cell]
  return cell;
  }
Run Code Online (Sandbox Code Playgroud)

这是它的要点.如上所述,其他事情可能是:

  • 让ITunesStore实现UITableViewDataSource,然后直接处理tableview数据源方法 - 如果这样做,你不想让iTunesStore成为单例.您可以将iTunesStore的实例设置为tableview的委托,而不是viewcontroller.这种方法有利有弊.
  • 我没有显示任何真正的异步行为或缓存这个应用程序正在哭泣
  • 这确实展示了如何完成一些模型职责并分离一些tableview数据源问题.

希望这有助于为您提供有关您可能探索的不同方向的一些想法.快乐的编码!