UITableView reloadData does nothing (UITableView is not nil)
I'm building my first real app, and you guys has already been most helpful, but I've been struggling with the tableView not updating. I hope that someone here could shed some light over this, and maybe come up with any ideas on other stuff i might have missed or done unnecessarily complicated.
For now, the app is supposed to do the following:
Things I've double checked: connections between tableview and delegate, datasource and outlet; that the tableView is not nil; that the datasource itself has been accurately updated;
Everything works up to that last point (7). It seems that myTableView is not nil at the time. Ideas? And please tell me if you would need to see more of my code.
I've also looked a bit at the methods beginUpdates and endUpdates, but it seems to me that they focuses on a few changes at a time and user interactivity. I would like to just reload the entire table based on user choices (ie would like to reflect a whole other SQL select string depending on the current user login). Or is there another, even better way to do that?
Thanks in advance!
Here's a rather good chunk of the code:
#import "FirstViewController.h"
@interface FirstViewController ()
@end
@implementation FirstViewController
#import "FirstViewController.h"
@synthesize myTextView, myTableViewDataSource, myFetchedData, resultat, tablesAndChecks, tablesArr, checksArr, tablesToRequest,receivedData, receivedDataString, SQL, sqlStatementsArr, failedSqlStatementsArr, failedSqlStatementsCodeArr, dbloop1;
#pragma mark Table view methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(@"Konfigurerar tableView"); //swedish for "Configuring tableView"
if(myTableView.dataSource==nil){
NSLog(@"datasource = nil");
}else{
NSLog(@"datasource != nil"); //This prints in log
}
NSLog(@"%d",[myTableViewDataSource count]); //prints "19" in log
return [myTableViewDataSource count];
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(@"calling cellForRowAtIndexPath"); //This does NOT print in log
static NSString *CellIdentifier = @"myCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Set up the cell...
cell.textLabel.font = [UIFont fontWithName:@"Helvetica" size:15];
cell.textLabel.text = [NSString stringWithFormat:@"Tabell %d: %@", [indexPath row], [myTableViewDataSource objectAtIndex:[indexPath row]]];
return cell;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(@"connection did finish loading");
//...
//script that receives a long SQL-string from the server
//and then updates the database with it goes here
//...
//Ok, so now the database has updated correctly, and it's time
//to update the tableview so that it reflects the new data.
//
//Get data from database...
NSMutableArray * tempArray = [[NSMutableArray alloc] initWithCapacity:0];
if (sqlite3_open(dbpath, &contactDB) == SQLITE_OK)
{
NSLog(@"Databasen öppnad");
NSString *beginSQL = [NSString stringWithFormat: @"SELECT name FROM sqlite_master WHERE type='table' ORDER BY name;"];
const char *begin_stmt = [beginSQL UTF8String];
sqlite3_prepare_v2(contactDB, begin_stmt, -1, &statement, NULL);
while(sqlite3_step(statement) == SQLITE_ROW) {
char *col1 = (char *)sqlite3_column_text(statement, 0);
if (col1 !=NULL){
[tempArray addObject:[NSString stringWithUTF8String: col1]];
}
}
if (sqlite3_step(statement) == SQLITE_DONE)
{
NSLog(@"#####%s; Done: %@", sqlite3_errmsg(nil), beginSQL);
} else {
NSLog(@"#####%s; Error with string: %@; Errcode: %d Errmsg: %s", sqlite3_errmsg(nil), beginSQL, sqlite3_errcode(contactDB), sqlite3_errmsg(nil));
}
NSLog(@"%d", sqlite3_finalize(statement));
sqlite3_close(contactDB);
//update the datasource to the values of tempArray
myTableViewDataSource = tempArray;
//Some logging to see that the updated data is in the array... (which it is)
NSLog(@"myTableViewDataSource count: %d",[myTableViewDataSource count]);
for (i=0; i<[myTableViewDataSource count]; i++) {
NSLog(@"%@",[myTableViewDataSource objectAtIndex:i]);
}
}
//Finally, check so that myTableView isn't nil and can receive messages
if(myTableView == nil){
NSLog(@"NILCHECK mytableview is nil!");
}else{
NSLog(@"NILCHECK mytableview is NOT nil!"); //This is printed out to the log
}
//Reload data -> nothing happens...
[myTableView reloadData];
}
- (void)fetchData
{
//function that gets current checksums for all db tables on the server, compares them to the local database
//and then requests an SQL-string from the server to update the tables that needs it.
//I don't think this is relevant for my problem, and it runs fine anyways.
//The last thing it does is setting up a NSURLConnection to communicate with
//the server (sending which tables to request via POST and then getting the SQL-string as the server response)
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:request delegate:self];
if (theConnection) {
//receivedData = [NSMutableData data];
NSLog(@"ReceivedData är: %d", [receivedData length]);
} else {
NSLog(@"Connection Failed!");
}
//All done here, now the ReceivedData method takes over
}
}
Update:
This is my viewDidLoad method:
- (void)viewDidLoad
{
//creates database and fills "tempArray" with data
NSLog(@"%d", sqlite3_finalize(statement));
sqlite3_close(contactDB);
myTableViewDataSource = tempArray;
NSLog(@"myTableViewDataSource count: %d",[myTableViewDataSource count]);
for (i=0; i<[myTableViewDataSource count]; i++) {
NSLog(@"%@",[myTableViewDataSource objectAtIndex:i]);
}
}
myTableView = [[UITableView alloc] initWithFrame:self.view.frame style:UITableViewStylePlain];
myTableView.delegate = self; //Added this after comment (1)
myTableView.dataSource = self; //Added this after comment (2)
}
Update: After adding this:
myTableView.delegate = self;
myTableView.dataSource = self;
to viewDidLoad, the tableView:numberOfRowsInSection:
is called, and dataSource is not nil, but tableView:cellForRowAtIndexPath:
is not called, and the table is not updated.
Update 2: Here's my header file:
//
// FirstViewController.h
// OHBSYS Storyboards
//
// Created by David Forsberg on 2012-09-25.
// Copyright (c) 2012 David Forsberg. All rights reserved.
//
#import <UIKit/UIKit.h>
#import <sqlite3.h>
@interface FirstViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>{
NSString *databasePath;
sqlite3 *contactDB;
UITextView *myTextView;
UITableView *myTableView;
NSMutableArray *myTableViewDataSource;
NSMutableString * tableRowCount;
NSMutableArray * dbloop1;
//And a bunch of other variables here
}
@property (retain, nonatomic) IBOutlet UITextView *myTextView;
@property (nonatomic, retain) IBOutlet UITableView *myTableView;
@property (nonatomic, retain) IBOutlet NSMutableArray *myTableViewDataSource;
- (IBAction) fetchData;
@property (nonatomic) NSString * tableRowCount;
@property (nonatomic, retain) NSMutableArray * dbloop1;
//A bunch of other properties here as well
@end
Update 3:
I've tried checking the values using breakpoints.
Breakpoint inside tableview:numberofrowsinsection:
(lldb) po self.myTableView
(UITableView *) $0 = 0x0d13ca00 <UITableView: 0xd13ca00; frame = (0 20; 768 1004); clipsToBounds = YES; layer = <CALayer: 0x2a3d30>; contentOffset: {0, 0}>
(lldb) po self.myTableView.delegate
(objc_object *) $1 = 0x0ce99500 <FirstViewController: 0xce99500>
(lldb) po self.myTableView.dataSource
(objc_object *) $2 = 0x0ce99500 <FirstViewController: 0xce99500>
(lldb) po self.myTableViewDataSource
(NSMutableArray *) $3 = 0x0029fb20 <__NSArrayM 0x29fb20>(
CONTACTS,
sqlite_sequence
)
(lldb)
Breakpoint after the db is updated, right before reloadData is called:
(lldb) po self.myTableView
(UITableView *) $4 = 0x0d13ca00 <UITableView: 0xd13ca00; frame = (0 20; 768 1004); clipsToBounds = YES; layer = <CALayer: 0x2a3d30>; contentOffset: {0, 0}>
(lldb) po self.myTableView.delegate
(objc_object *) $5 = 0x0ce99500 <FirstViewController: 0xce99500>
(lldb) po self.myTableView.dataSource
(objc_object *) $6 = 0x0ce99500 <FirstViewController: 0xce99500>
(lldb) po self.myTableView.dataSource //(accidentally hit that twice)
(objc_object *) $7 = 0x0ce99500 <FirstViewController: 0xce99500>
(lldb) po self.myTableViewDataSource
(NSMutableArray *) $8 = 0x0ce6baa0 <__NSArrayM 0xce6baa0>(
CONTACTS,
meta_tablechecksums,
prot_multicoltest,
prot_multicoltest_4,
prot_multicoltest_4_desc,
prot_multicoltest_desc,
sqlite_sequence,
superadmin_filefolders,
superadmin_files,
superadmin_imagefolders,
superadmin_images,
sys_customers,
sys_fieldlooks,
sys_fieldtypes,
sys_formtables,
sys_pages,
sys_subpages,
sys_userroles,
sys_users
)
(lldb)
Breakpoint AT reloadData line:
(lldb) po self.myTableView
(UITableView *) $9 = 0x0d13ca00 <UITableView: 0xd13ca00; frame = (0 20; 768 1004); clipsToBounds = YES; layer = <CALayer: 0x2a3d30>; contentOffset: {0, 0}>
(lldb) po self.myTableView.delegate
(objc_object *) $10 = 0x0ce99500 <FirstViewController: 0xce99500>
(lldb) po self.myTableView.dataSource
(objc_object *) $11 = 0x0ce99500 <FirstViewController: 0xce99500>
(lldb) po self.myTableViewDataSource
(NSMutableArray *) $12 = 0x0ce6baa0 <__NSArrayM 0xce6baa0>(
CONTACTS,
meta_tablechecksums,
prot_multicoltest,
prot_multicoltest_4,
prot_multicoltest_4_desc,
prot_multicoltest_desc,
sqlite_sequence,
superadmin_filefolders,
superadmin_files,
superadmin_imagefolders,
superadmin_images,
sys_customers,
sys_fieldlooks,
sys_fieldtypes,
sys_formtables,
sys_pages,
sys_subpages,
sys_userroles,
sys_users
)
(lldb)
Breakpoint inside tableview:numberofrowsinsection: after the db was updated and the reloadData command was run:
(lldb) po self.myTableView
(UITableView *) $13 = 0x0d13ca00 <UITableView: 0xd13ca00; frame = (0 20; 768 1004); clipsToBounds = YES; layer = <CALayer: 0x2a3d30>; contentOffset: {0, 0}>
(lldb) po self.myTableView.delegate
(objc_object *) $14 = 0x0ce99500 <FirstViewController: 0xce99500>
(lldb) po self.myTableView.dataSource
(objc_object *) $15 = 0x0ce99500 <FirstViewController: 0xce99500>
(lldb) po self.myTableViewDataSource
(NSMutableArray *) $16 = 0x0ce6baa0 <__NSArrayM 0xce6baa0>(
CONTACTS,
meta_tablechecksums,
prot_multicoltest,
prot_multicoltest_4,
prot_multicoltest_4_desc,
prot_multicoltest_desc,
sqlite_sequence,
superadmin_filefolders,
superadmin_files,
superadmin_imagefolders,
superadmin_images,
sys_customers,
sys_fieldlooks,
sys_fieldtypes,
sys_formtables,
sys_pages,
sys_subpages,
sys_userroles,
sys_users
)
(lldb)
I don't see the myTableView being synthesized. Also are the tableView datasource methods called, upon doing the reloadData ?
If not, double check and verify that the myTableView delegate is set correctly. If you have correctly connected the Table to the nib and you have an outlet you can set it up also in code, ie in the viewDidLoad method, by setting:
myTableView.delegate = self;
@Lefteris was right. You may already have this but I can't see your header file. In the view controller's header file, add a property to maintain a reference to the tableview:
@property (nonatomic, strong) UITableView *myTableView;
Then in your implementation file:
@synthesize myTableView = myTableView_;
Finally, within the implementation file, change all references to the tableview from myTableView
to self.myTableView
and see if you suddenly start getting your delegate callbacks.
The basic problem in this was a lack of a Controller in the MVC application. I read up on the basic concept and built it again from scratch - this time, the right way.
链接地址: http://www.djcxy.com/p/64474.html