简体   繁体   English

UITableView reloadData什么都不做(UITableView不是nil)

[英]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. 我正在构建我的第一个真正的应用程序,你们已经是最有帮助的,但我一直在努力与tableView不更新。 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: 目前,该应用程序应该执行以下操作:

  1. Fill table with data from the sqlite db (basically just list all tables) 使用来自sqlite db的数据填充表(基本上只列出所有表)
  2. User presses button (which triggers fetchData method) 用户按下按钮(触发fetchData方法)
  3. (void)fetchData compares local db to server db checksums (void)fetchData将本地数据库与服务器数据库校验和进行比较
  4. (void)fetchData sets up a NSURLConnection, communicating with the server thru POST (void)fetchData设置NSURLConnection,通过POST与服务器通信
  5. When connection has received all data, it updates the local db 当连接收到所有数据时,它会更新本地数据库
  6. The tableView dataSource (which is a NSMutableArray) is updated with the new db data tableView dataSource(它是一个NSMutableArray)使用新的db数据进行更新
  7. The tableview gets updated and lists all tables in the database [myTableView reloadData] is called tableview得到更新,并列出数据库中的所有表[myTableView reloadData]被调用

Things I've double checked: connections between tableview and delegate, datasource and outlet; 我经过双重检查的事情:tableview和delegate,datasource和outlet之间的连接; that the tableView is not nil; tableView不是nil; that the datasource itself has been accurately updated; 数据源本身已经准确更新;

Everything works up to that last point (7). 一切都达到了最后一点(7)。 It seems that myTableView is not nil at the time. 似乎myTableView当时并不是零。 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. 我还看了一下beginUpdates和endUpdates方法,但在我看来,他们一度关注一些变化和用户交互性。 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). 我想根据用户选择重新加载整个表(即希望根据当前用户登录反映整个其他SQL选择字符串)。 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: 这是我的viewDidLoad方法:

- (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. to viewDidLoad, tableView:numberOfRowsInSection:被调用,而dataSource不是nil,但是没有调用tableView:cellForRowAtIndexPath:并且表没有被更新。

Update 2: Here's my header file: 更新2:这是我的头文件:

    //
//  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: 更新3:

I've tried checking the values using breakpoints. 我已经尝试使用断点检查值。

Breakpoint inside tableview:numberofrowsinsection: 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: 数据库更新后的断点,就在调用reloadData之前:

(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: 断点AT reloadData行:

(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: tableview中的断点:numberofrowsinsection:在更新db并运行reloadData命令之后:

(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. 我没有看到myTableView被合成。 Also are the tableView datasource methods called, upon doing the reloadData ? 在执行reloadData时,还调用了tableView数据源方法吗?

If not, double check and verify that the myTableView delegate is set correctly. 如果没有,请仔细检查并验证myTableView委托是否设置正确。 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: 如果您已正确地将表连接到笔尖并且您有一个插座,您也可以在代码中设置它,即在viewDidLoad方法中,通过设置:

myTableView.delegate = self;

@Lefteris was right. @Lefteris是对的。 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: 在视图控制器的头文件中,添加一个属性以维护对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. 最后,实现文件中,更改为从tableview中所有引用myTableViewself.myTableView ,看看你是否突然开始让你的委托回调。

The basic problem in this was a lack of a Controller in the MVC application. 其中的基本问题是MVC应用程序中缺少Controller。 I read up on the basic concept and built it again from scratch - this time, the right way. 我阅读了基本概念并从头开始重新构建 - 这一次,正确的方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM