#ios #objective-c #arrays #tableview
#iOS #objective-c #массивы #просмотр таблицы
Вопрос:
Я пытаюсь выполнить довольно стандартную операцию, которая в основном заключается в получении всех записей из моей локальной базы данных SQLITE, затем получении дополнительных данных из веб-формы, объединении этих данных (которые являются NSMutableArray) и отображении их в табличном виде. В viewDidLoad
массиве есть все необходимые элементы, но в numberOfRowsInSection:
нем равно нулю. Из-за этого я не могу отображать элементы в tableview. Так где же он может быть установлен на ноль? Спасибо вам за любую помощь. Код для InboxViewControler.m
//
// ArticleViewController.m
// ReadLater
//
// Created by Ibragim Gapuraev on 09/06/2014.
// Copyright (c) 2014 Sermilion. All rights reserved.
//
#import "InboxViewController.h"
#import "LoginViewController.h"
#import "SHCTableViewCell.h"
@interface InboxViewController ()
@end
@implementation InboxViewController
@synthesize db, articles, response, jsonData;
- (NSMutableArray* ) articles
{
if (!articles) {
articles = [[NSMutableArray alloc] initWithCapacity:20];
}
return articles;
}
- (Database* ) db
{
if (!db) {
db = [[Database alloc] init];
}
return db;
}
//---------------------------------Getting data from web-------------------------------------------//
/**
The method will connect to a given url and send date of article that has been added at last.
Then, connectionDidFinishLoading will receive json array of all articles, that have been added to server database after that time
**/
#pragma mark Connection to server
- (void) makeConnetion:(id)data
{
NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://localhost/nextril/index.php"] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:15.0];
NSURLConnection * connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
//send id of article that was added last, to server,
//which will return json arrya of all articles with id greater then the one sent
[request setHTTPMethod:@"POST"];
[request setHTTPBody:[data dataUsingEncoding:NSUTF8StringEncoding]];
if (connection) {
NSLog(@"viewWillAppear: Connecting to server to get data...");
}else{
NSLog(@"viewWillAppear: Error while connecting...");
}
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData*)data
{
response = [[NSData alloc] initWithData:data];
}
//Check if data been received
- (void) connectionDidFinishLoading:(NSURLConnection *)connection
{
if(sizeof(response)>0){
//NSLog(@"Got response from server %@", response);
NSError* error;
NSArray* json = [NSJSONSerialization
JSONObjectWithData:response //1
options:kNilOptions
error:amp;error];
self.jsonData = [[NSMutableArray alloc] initWithArray:json];
int count = 0;
[self.db openDatabase];
BOOL added = false;
BOOL addedToUser = false;
NSLog(@"jsonData %d", jsonData.count);
for (int i=0; i<self.jsonData.count; i ) {
NSDictionary *item = [self.jsonData objectAtIndex:i];
NSString* content = [item objectForKey:@"content"];
NSString* author = [item objectForKey:@"author"];
NSString* date = [item objectForKey:@"date"];
NSString* url = [item objectForKey:@"url"];
NSString* tags = [item objectForKey:@"tags"];
NSInteger archived = [[item objectForKey:@"archived"]integerValue];
NSString* title = [item objectForKey:@"title"];
//NSLog(@"",);
Article* article = [[Article alloc]initWithId:0 content:content author:author date:date url:url tags:tags arhived:archived title:title];
added = [self.db addArticleToArticleDB:article];
if (added == true) {
NSInteger last_id = [self.db getLastArticleID];
article.article_id = last_id;
[self.articles addObject:article];
addedToUser = [self.db addArticleToUserArticleDB:article];
}
count ;
}
if (added == true amp;amp; addedToUser == true) {
NSLog(@"connectionDidFinishLoading: Articles has been imported. Size: %d %lu", jsonData.count, (unsigned long)jsonData.count);
}else{
NSLog(@"connectionDidFinishLoading: Failed to import article.");
}
NSArray *importedArticles = [self.db importAllArticlesForUser:16 archived:0];
[self.articles addObjectsFromArray:importedArticles];
[self.db closeDatabase];
}else{
NSLog(@"connectionDidFinishLoading: Did not get resopnse from server: %@", response);
}
connection = nil;
}
//----------------------------------------------------------------------------------------------------
#pragma mark TODO: work out why data from server loads only after second login
#pragma mark view
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.db openDatabase];
NSString* date_added = [self.db getLastArticleDate];
[self makeConnetion:(id)date_added];
NSLog(@"viewWillAppear: self.articles: %d", self.articles.count);
[self.db closeDatabase];
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.tableView.dataSource = self;
self.tableView.delegate = self;
self.tableView.separatorColor = [UIColor clearColor];
self.tableView.backgroundColor = [UIColor blackColor];
[self.tableView registerClass:[SHCTableViewCell class] forCellReuseIdentifier:@"Content"];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
NSLog(@"numberOfRowsInSection: self.articles: %d", self.articles.count);
return self.articles.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Content";
SHCTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
cell.textLabel.backgroundColor = [UIColor clearColor];
NSMutableArray* safeArticles = self.articles;
// Configure the cell...
Article* article = [safeArticles objectAtIndex:indexPath.row];
NSString *listingKey = article.title;
NSString *listingValues = article.url;
cell.textLabel.text = listingKey;
cell.detailTextLabel.text = listingValues ;
cell.delegate = self;
cell.todoItem = article;
return cell;
}
#pragma mark cell atributes
-(UIColor*)colorForIndex:(NSInteger) index {
NSUInteger itemCount = self.articles.count - 1;
float val = ((float)index / (float)itemCount) * 0.6;
return [UIColor colorWithRed: 1.0 green:val blue: 0.0 alpha:1.0];
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 70.0f;
}
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
cell.backgroundColor = [self colorForIndex:indexPath.row];
}
#pragma mark TODO delete from server database
//method to delete an article form view and to call method to delete from database, as well as form server database
-(void)deleteArticle:(Article*)articleToDelete {
. . .
}
#pragma mark TODO delete from server database
//method to delete an article form view and to call method to delete from database, as well as form server database
-(void)archiveArticle:(Article*)articleToArchive {
. . .
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
Комментарии:
1. Вы пробовали вызывать [TableView reloadData]; после получения всех необходимых данных?
2. Я поставил [TableView reloadData]; сразу после цикла for в connectionDidFinishLoading: и это действительно сработало. Спасибо. Итак, в каком случае, как правило, я должен вызывать этот метод где-либо еще?
Ответ №1:
A tableView
вызывает datasource
методы для заполнения себя сразу после viewDidLoad
. Если в этот момент источник данных (который обычно является массивом) пуст, в TableView ничего не появится. Вот почему нужно вызывать reloadData
после создания источника данных. Это особенно необходимо в случаях, когда источник данных извлекается асинхронно.
Согласно документации Apple о reloadData
:
Вызовите этот метод, чтобы перезагрузить все данные, которые используются для построения таблицы, включая ячейки, верхние и нижние колонтитулы разделов, массивы индексов и так далее. Для повышения эффективности в табличном представлении повторно отображаются только те строки, которые видны. Он корректирует смещения, если таблица сжимается в результате перезагрузки. Делегат представления таблицы или источник данных вызывает этот метод, когда он хочет, чтобы представление таблицы полностью перезагрузило свои данные. Его не следует вызывать в методах, которые вставляют или удаляют строки, особенно в блоке анимации, реализованном с вызовами beginUpdates и endUpdates
Ответ №2:
Воспользовался советом @akashg и добавил [self.TableView reloadData]; после извлечения данных. И это сработало. Хотя я не знаю механизма, почему это произошло. По крайней мере, это работает) Любой желающий может добавить свое объяснение. Спасибо.
Комментарии:
1. Об этом особо нечего сказать — вам нужно вызывать reloadData (или один из других методов, который загружает отдельные строки или разделы) всякий раз, когда данные, которые вы хотите отобразить, изменяются. Методы источника данных табличного представления вызываются сразу после viewDidLoad , поэтому, если у вас есть какой-либо асинхронный процесс для получения данных, вам нужно вызвать reloadData по завершении загрузки. Вызов этого метода приводит к тому, что табличное представление вызывает свои методы источника данных (NumberOfSections:, numberOfRowsInSection: и т.д.).