Обновление данных XML и обновление UITableView - PullRequest
0 голосов
/ 14 декабря 2009

Я разрабатываю приложение для iPhone, которое использует TableView для отображения данных XML. Данные XML поступают из внешнего ресурса, анализируются и помещаются в объект для использования в качестве источника данных таблицы. Приложение использует UITabBar и несколько ViewControllers, все они программно созданы и используют один и тот же источник данных.

Все хорошо, но я хотел бы реализовать кнопку обновления, чтобы пользователь мог обновить содержимое (глобально, поэтому все ViewControllers должны быть обновлены). Парсер снова запросит XML и создаст новый объект. Проблема, с которой я столкнулся, заключается в том, что я не могу снова заполнить табличное представление моими новыми данными. Я получаю обновленный объект данных. На самом деле обновление таблицы является проблемой. Я попытался установить setDataSource и вызвать reloadData, но это приводит к сбою из-за нераспознанного селектора.

Материал XML вызывается из моего AppDelegate, и вся логика синтаксического анализа находится в Parser.m. Функция обновления вызывается в RootViewController.m, который реализует протокол UITableViewDataSource:

- (void)refreshXMLFeed:(id)sender {
  NSArray *tableControllersData = [appDelegate getData];
  [self.tableView setDataSource: tableControllersData];
  [self.tableView reloadData];  
}

Как бы я подошел к этому вопросу? Должен получить новые данные и перезагрузить табличное представление в RootViewController, как я пытался сделать. Или же следует выполнить анализ данных в AppDelegate и только перезагрузить TableView в RootViewController.

При необходимости я могу обновить свой вопрос необходимым кодом, я не уверен, какие части актуальны на данный момент.

RootViewController.h:

#import <UIKit/UIKit.h>

@interface RootViewController : UITableViewController {
  MyAppDelegate *appDelegate;
  NSArray *tableDataArray;
}

@property (nonatomic, retain) NSArray *tableDataArray;

- (IBAction)refreshXMLFeed:(id)sender;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil tableDataSource:(NSArray*)tableData;

@end

RootViewController.m:

#import "CustomCell.h"
#import "MyAppDelegate.h"
#import "RootViewController.h"
#import "DetailViewController.h"

@implementation RootViewController
@synthesize tableDataArray;

- (void)viewDidLoad {
  [super viewDidLoad];
}

//Override the default initWithNibName method
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil tableDataSource:(NSArray*)tableData {
  if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
    // Custom initialization
    tableDataArray = [tableData retain];   
  }
  return self;
}

-(void)viewWillAppear:(BOOL)animated {
  appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];    
  [super viewWillAppear:animated];
  //Set the colour of the navigationController and add buttons
  self.navigationController.navigationBar.tintColor = [UIColor blackColor];

  //Add the refresh button
  UIBarButtonItem* refreshButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh target:self action:@selector(refreshXMLFeed:)];
  [self.navigationItem setLeftBarButtonItem:refreshButton animated:YES];
  [refreshButton release];  
}

#pragma mark Table

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
  return [self.tableDataArray count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
  static NSString *CustomCellIdentifier = @"CustomCellIdentifier";
  CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier: CustomCellIdentifier];
  if (cell == nil) {
    NSArray *cellNib = [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:self options:nil];
    for (id oneObject in cellNib) {
      if ([oneObject isKindOfClass:[CustomCell class]]) {
        cell = (CustomCell *)oneObject;
      }
    }
  }

  NSUInteger row = [indexPath row];
  NSDictionary *rowData = [self.tableDataArray objectAtIndex:row];
  cell.colorLabel.text = [rowData objectForKey:@"Type"];
  cell.nameLabel.text = [rowData objectForKey:@"Name"];
  UIImage *image = [UIImage imageNamed:[rowData objectForKey:@"Icon"]];
  cell.image = image;
  return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
  NSString *selectedRow = [tableDataArray objectAtIndex:indexPath.row];

  DetailViewController *detailViewController = [[DetailViewController alloc] initWithNibName:@"DetailView" bundle:[NSBundle mainBundle]];
  detailViewController. selectedRow = selectedRow;
  [self.navigationController pushViewController:detailViewController animated:YES];

  UIBarButtonItem *backButton = [[UIBarButtonItem alloc] init];
  backButton.title = @"Back";
  self.navigationItem.backBarButtonItem = backButton;
  [backButton release];  
  [detailViewController release];
  detailViewController = nil;
}

#pragma mark Refresh

- (void)refreshXMLFeed:(id)sender {
  NSArray *tableControllersData = [appDelegate getData];
  [self.tableView setDataSource: tableControllersData];
  [self.tableView reloadData];  
}

- (void)didReceiveMemoryWarning {
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];

    // Release any cached data, images, etc that aren't in use.
}

- (void)viewDidUnload {
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
}


- (void)dealloc { 
    [super dealloc];
}

@end

Ответы [ 2 ]

3 голосов
/ 15 декабря 2009

Вы должны устанавливать источник данных только один раз, и он не должен быть NSArray. Контейнер данных, из которого вы извлекаете свои записи, может измениться, но источник данных всегда должен быть одинаковым. В большинстве случаев источником данных должен быть только ваш контроллер представления. Тогда ваш контроллер представления должен реализовать методы в UITableViewDataSource протоколе , включая:

– tableView:cellForRowAtIndexPath:  required method
– numberOfSectionsInTableView:
– tableView:numberOfRowsInSection:  required method
– sectionIndexTitlesForTableView:
– tableView:sectionForSectionIndexTitle:atIndex:
– tableView:titleForHeaderInSection:
– tableView:titleForFooterInSection:

NSArray не отвечает ни на один из этих методов, поэтому вы получаете нераспознанное сообщение селектора. Вы должны реализовать их самостоятельно.

Вы должны ознакомиться с Руководством по программированию табличного представления , чтобы понять, как эффективно использовать представления таблицы.

С уважением.

ОБНОВЛЕНИЕ: Вот небольшой код, который может вам помочь. В вашем RootViewController создайте экземпляр NSArray с помощью alloc / init в -viewDidLoad. Назовите это элементами:

- (void)viewDidLoad;
{
    [super viewDidLoad];
    items = [[NSArray alloc] init];
}

Затем реализуйте делегаты источника данных вашего табличного представления следующим образом:

- (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section
{
    return [items count];
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;
{
    return 1;
}

Тогда вам нужно реализовать свой cellForRowAtIndexPath:

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

    cell = [tv dequeueReusableCellWithIdentifier:@"Cell"];
    if (cell == nil)
    {
        cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:@"Cell"] autorelease];

    }

    // Get your item from the items array here
    NSDictionary *item = [items objectAtIndex:[indexPath row]];
    NSString *text = [item valueForKey:@"text"];

    [[cell textLabel] setText:text];

    return cell;

}

Этот код предполагает, что объекты в вашем NSArray являются NSDictionaries. Если вы используете какой-либо пользовательский объект, приведите объект по указанному пути индекса к вашему пользовательскому типу, а затем используйте его поля.

Когда у вас появятся новые данные и вам потребуется перезагрузить табличное представление, вы просто перераспределите свои элементы NSArray и затем вызовете reloadData для табличного представления. Скажем, у вас произошла перезагрузка:

- (void)didReciveNewData:(NSArray*)newItems;
{
    if (items) [items release], items = nil;
    items = [newItems copy];
    [tableView reloadData];
}

Это заставит табличное представление запросить свой контроллер представления о количестве отображаемых строк и о ячейках для каждой строки снова, которые предоставляются путем доступа к количеству и содержимому NSArray.

НТН.

0 голосов
/ 14 декабря 2009

Я предполагаю, что ваши данные загружаются асинхронно в вашем методе getData (если это не так), который обновляет / делает недействительной ссылку на источник данных, когда пользователь меньше всего этого ожидает, вызывая сбой, когда пользователь пытается сделать с устаревшим указателем на его данные.

Просто убедитесь, что вы никогда не изменяете содержимое tablecontrollersdata из другого потока.

или, может быть, вы пытаетесь использовать coredata, в этом случае я понятия не имею.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...