从互联网上获取表格数据时,有人能用UItableview解释MVC吗? [英] Can anybody explain MVC in terms of UItableview when getting data for the table from the internet?

查看:110
本文介绍了从互联网上获取表格数据时,有人能用UItableview解释MVC吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Can anybody explain to me how MVC works when it comes to UITableView especially when getting data from the internet.

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

I would exactly like to know what is the model, view and controller when it comes to a UItableview

我编写了以下ViewController代码,该代码从互联网上获取数据并使用AFNetworking框架将其显示在表格上。

I have written the following ViewController code which sources data from the internet and displays it on a table using AFNetworking framework.

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

Could you please tell me how to change this and separate it into model, view and controller. I have also written a refresh class, which i am guessing is a part of the model. Could you tell me how exactly do i make changes and make it a part of the model.

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

EDIT : The below answers help me understand the concept theoritically, Could someone please help me in changing the code accordingly( By writing a new class on how to call the array to this class and populate the table because i am using a json parser). I would like to implent it. And not just understand it theoritically.

#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


推荐答案

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

It's a pretty big question you are asking. But let me answer by making it as simple as possible.


  • 模型 - 您的数据源;最终它是您的Web服务数据

  • 控制器应该是拥有表视图的东西,并在视图中调整设置属性并对视图中的事件做出反应并进行更改,如需要,对于模型

  • 查看 - 表格视图和表格视图单元格的组合

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

There are a lot of approaches to coordinating between your web data and your table view but one I might suggest would be to refactor your web service calls into a separate store class - say iTunesStore - have that class be responsible for making the calls to the service and setting an internal array with the results, it should also be able to return a row count as well as a specific item for a given row index.

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

You then have this class respond to calls for the required table view delegate methods. Other things to consider, make this other class a singleton, have it conform to UITableviewDatasource protocol itself and assign it as the table views' data source.

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

Like I said, a big question with a lot of options for you, but I've given you some things to consider in terms of where to go next.

UPDATE

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

UPDATE
I'm adding some code examples to help clarify. At the outset, I want to make clear that I am not going to provide the total solution because doing so would require me to assume too much in terms of the necessary actual solution -- and because there are a few different ways to work with AFNetworking, web services, etc....and I don't want to get side tracked going down that rabbit hole. (Such as caching data on the client, background tasks & GCD, etc...) Just showing you how to wire up the basics -- but you will definitely want to learn how to use AFNetworking on a background task, look into Core Data or NSCoding for caching, and a few other topics to do this sort of thing correctly.

只需说出合适的解决方案:

- 您不希望同步呼叫您的网络服务

- 您也不希望每次都重新请求相同的数据 - 即不要从服务中重新下载相同的记录,除非它已更改为
- 我不是显示如何在这里做这些事情,因为它超出了范围;查看下面的书籍推荐以及此链接以了解这些主题 Ray Wenderlich - 使用网络服务同步核心数据

Suffice it to say that in a proper solution:
- You don't want to be calling your web service synchronously
- You also don't want to be re-requesting the same data every time - ie don't re-download the same record from the service unless its changed
- I am not showing how to do those things here because its way beyond the scope; look a the book recommendation below as well as this link to get an idea about these topics Ray Wenderlich - sync Core Data with a web service

对于您的数据服务代码,我会创建一个商店类。 (帮自己一个忙,如果你还没有它,可以获得Big Nerd Ranch iOS书。

iOS编程第4版

For your data services code, I would create a 'store' class. (do yourself a favor and get the Big Nerd Ranch iOS book if you don't already have it.
iOS Programming 4th Edition

将以下代码带入盐中 - 原因我不能去我无法通过我的Mac(在Win机器上)执行此操作,而且我也无法复制甚至通过电子邮件发送代码...所以我在StackOverflow编辑器中执行所有操作...

我的iTunesStore合约(标题文件)如下所示:

My iTunesStore contract (header file) would look something like:

// 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

......执行情况如下:

...and the implementation would look something like:

// 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

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

I now have a 'store' object singleton I can use to get records, return a given record and also tell me a record count. Now I can move a lot of the logic doing this from the viewcontroller.

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

Now I don't need to do this in your VC viewDidLoad method. Ideally, you would have an async method in your store object to get records and a block to call you back once records are loaded. Inside the block you reload records. The signature for something like that 'might' look like:

[[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
}];

您的视图控制器数据源方法现在如下所示:

Your view controller data source methods now look like:

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

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

Inside cellForRowAtIndexPath - I also call my store object to get the correct record

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

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

  // ... configure cell]
  return cell;
  }

这就是它的要点。其他要做的事情,如上所述:

That's the gist of it. Other things to do, as noted above would be:


  • 让ITunesStore实现UITableViewDataSource,然后直接处理tableview数据源方法 - 如果你这样做的话这你不想让iTunesStore成为单身人士。您可以将iTunesStore的实例设置为tableview的委托,而不是viewcontroller。这种方法有利有弊。

  • 我没有显示任何真正的异步行为或缓存这个应用程序正在为此而哭泣

  • 这确实展示了如何完成一些模型职责并分离一些tableview数据源问题。

希望这会有所帮助给你一些关于你可能探索的不同方向的想法。
快乐编码!

Hopefully this will help to give you some ideas about different directions you might explore. Happy coding!

这篇关于从互联网上获取表格数据时,有人能用UItableview解释MVC吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆