JSON请求后以编程方式TableView不会重新加载数据

Posted

技术标签:

【中文标题】JSON请求后以编程方式TableView不会重新加载数据【英文标题】:Programmatically TableView won't reloadData after JSON request 【发布时间】:2013-08-30 17:37:01 【问题描述】:

我正在尝试使用有效的 TableView 填充 KGModal 视图 (https://github.com/kgn/KGModal),但在通过 JSON 获取数据后我无法重新加载数据,而不会导致应用崩溃。

cellForRowAtIndexPath 方法正在正确返回 JSON 结果,我认为问题出在 reloadData 方法中,因为 _tv 已被 KGModal 使用? itemNutriFeed.* 只是一个 JSON 模型。

//itemNutriModal.h

#import <UIKit/UIKit.h>

@interface itemNutriModal : UIViewController <UITableViewDataSource, UITableViewDelegate>
- (void)showNutri; //:(NSArray*)nutri;
@end

//itemNutriModal.m

#import "itemNutriModal.h"
#import "JSONModelLib.h"
#import "itemNutriFeed.h"
#import "KGModal.h"

@interface itemNutriModal () 
    itemNutriFeed* _feed;
    UITableView* _tv;


@end

@implementation itemNutriModal
- (void)didReceiveMemoryWarning

    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.


- (void)showNutri //:(NSArray*)nutri

  _tv = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 200, 400)];
  _tv.backgroundColor = [UIColor clearColor];
  _tv.scrollEnabled = FALSE;
 [_tv setDataSource:self];
 [_tv setDelegate:self];


[[KGModal sharedInstance] showWithContentView:_tv andAnimated:YES];

_feed = [[itemNutriFeed alloc] initFromURLWithString:@"http://c..../.../nutri.php?inid=1000"
                                          completion:^(JSONModel *model, JSONModelError *err) 

                                              //hide the loader view
                                              //[HUD hideUIBlockingIndicator];

                                              //json fetched
                                              NSLog(@"Results: %@", _feed.results);

                                              [_tv reloadData];


                                          ];

//;



//NSLog(@"SHOW NUTRIS!");


#pragma mark - TableView
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
    return 8;


- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView

    return 1;


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

    static NSString *CellIdentifier = @"nutriTableCell";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) 
    cell = [[UITableViewCell alloc]
            initWithStyle:UITableViewCellStyleValue1
            reuseIdentifier:CellIdentifier];


itemNutriModel* nutrivals = _feed.results[indexPath.row];

NSLog(@"nutrivals: %@", _feed.results);

cell.backgroundColor = [UIColor clearColor];
[cell.textLabel setTextColor:[UIColor whiteColor]];
[cell.textLabel setText:[NSString stringWithFormat:@"%@", nutrivals.type]];
[cell.detailTextLabel setText:[NSString stringWithFormat:@"%@", nutrivals.value]];

return cell;

@end

在 JSON 完成方法中放置 [[KGModal sharedInstance] showWithContentView:_tv andAnimated:YES]; 也会崩溃。

崩溃表明 EXC_BAD_ACCESS;

2013-08-30 19:13:56.634 xapp[91159:a0b] *** -[itemNutriModal tableView:cellForRowAtIndexPath:]: message sent to deallocated instance 0xd8add90

---- 第一个 cellForRowAtIndexPath 调用的堆栈跟踪(有效)----

2013-08-30 19:34:00.229 xapp[91619:a0b] Stack trace : (
    0   xapp                                0x0002dec3 -[itemNutriModal showNutri] + 483
    1   xapp                                0x0001a60f -[favouritesTableViewController tableView:accessoryButtonTappedForRowWithIndexPath:] + 175
    2   UIKit                               0x009baa25 -[UITableView _accessoryButtonAction:] + 310
    3   libobjc.A.dylib                     0x01b7c874 -[NSObject performSelector:withObject:withObject:] + 77
    4   UIKit                               0x008e424c -[UIApplication sendAction:to:from:forEvent:] + 108
    5   UIKit                               0x008e41d8 -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 61
    6   UIKit                               0x009daa5d -[UIControl sendAction:to:forEvent:] + 66
    7   UIKit                               0x009dae20 -[UIControl _sendActionsForEvents:withEvent:] + 577
    8   UIKit                               0x009da0cf -[UIControl touchesEnded:withEvent:] + 641
    9   UIKit                               0x00c5440f _UIGestureRecognizerUpdate + 7166
    10  UIKit                               0x00920e9a -[UIWindow _sendGesturesForEvent:] + 1291
    11  UIKit                               0x00921dba -[UIWindow sendEvent:] + 1030
    12  UIKit                               0x008f5b86 -[UIApplication sendEvent:] + 242
    13  UIKit                               0x008e035f _UIApplicationHandleEventQueue + 11421
    14  CoreFoundation                      0x01d7396f __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15
    15  CoreFoundation                      0x01d732fb __CFRunLoopDoSources0 + 235
    16  CoreFoundation                      0x01d903ce __CFRunLoopRun + 910
    17  CoreFoundation                      0x01d8fbf3 CFRunLoopRunSpecific + 467
    18  CoreFoundation                      0x01d8fa0b CFRunLoopRunInMode + 123
    19  GraphicsServices                    0x03125a27 GSEventRunModal + 192
    20  GraphicsServices                    0x0312584e GSEventRun + 104
    21  UIKit                               0x008e2f0b UIApplicationMain + 1225
    22  xapp                                0x0001313d main + 141
    23  libdyld.dylib                       0x03d05725 start + 0
)

---- 从 JSON 完成调用第二个 cellForRowAtIndexPath 的堆栈跟踪(异常)----

2013-08-30 19:34:00.332 xapp[91619:a0b] Stack trace : (
    0   xapp                                0x0002e1a6 __27-[itemNutriModal showNutri]_block_invoke + 230
    1   xapp                                0x0000b3d0 __58-[JSONModel(Networking) initFromURLWithString:completion:]_block_invoke_2 + 112
    2   libdispatch.dylib                   0x03a60818 _dispatch_call_block_and_release + 15
    3   libdispatch.dylib                   0x03a754b0 _dispatch_client_callout + 14
    4   libdispatch.dylib                   0x03a62a0e _dispatch_after_timer_callback + 98
    5   libdispatch.dylib                   0x03a754b0 _dispatch_client_callout + 14
    6   libdispatch.dylib                   0x03a6be6b _dispatch_source_latch_and_call + 150
    7   libdispatch.dylib                   0x03a66443 _dispatch_source_invoke + 411
    8   libdispatch.dylib                   0x03a636f6 _dispatch_main_queue_callback_4CF + 228
    9   CoreFoundation                      0x01e4fb6e __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 14
    10  CoreFoundation                      0x01d907eb __CFRunLoopRun + 1963
    11  CoreFoundation                      0x01d8fbf3 CFRunLoopRunSpecific + 467
    12  CoreFoundation                      0x01d8fa0b CFRunLoopRunInMode + 123
    13  GraphicsServices                    0x03125a27 GSEventRunModal + 192
    14  GraphicsServices                    0x0312584e GSEventRun + 104
    15  UIKit                               0x008e2f0b UIApplicationMain + 1225
    16  xapp                                0x0001313d main + 141
    17  libdyld.dylib                       0x03d05725 start + 0
)

【问题讨论】:

只是一个猜测,因为您决定通过不包括崩溃细节来强迫人们猜测,您的tableView:numberOfRowsInSection: 返回 8,它应该返回您的数据的实际计数,而不是硬编码常量。 抱歉,添加了异常,但调试对我来说是新的。 “完成 JSON 查询后”——具体是什么意思?哪条线?它在您的代码中,一些框架代码吗?你有堆栈跟踪吗?你启用僵尸了吗? 谢谢,已经添加了具体的错误和堆栈跟踪。 参考这个How to reloadData for tableview after data been prepared in a asynchronously method 【参考方案1】:

一旦您分配了数据源/委托,tableview 就会查询它的数据。您的 JSON 回调可能尚未完成运行。您需要检查它是否已完成,如果尚未完成则返回 0 行。如果您在 JSON 查询实际完成之前返回 8 行,您将崩溃。检查_feed中是否有numberOfRowsInSection中的数据,如果没有则返回0。

【讨论】:

返回 8 只是为了调试。在 JSON 完成设置 dataSource/delegate:self 时(但在 KGModal 中使用 _tv 之后),不会调用数据源方法。返回 _feed.results.count(未完成时为 0)显示一个带有单元格的模态框,但 _tv dataReload 仍然崩溃。 如果你稍后设置datasource/delegate,之后你将不得不手动调用reloadData。 试过了,reloadData 还是有问题,和主要问题一样。【参考方案2】:

似乎这是 KGModal 的问题 - 分配给 KGModal 对象时视图/控制器的解除分配意味着它不能再被 reloadData 命令操作。

我解决这个问题的方法是制作我自己的自定义 UIScrollView,在分配给模式窗口之前填充它。

【讨论】:

以上是关于JSON请求后以编程方式TableView不会重新加载数据的主要内容,如果未能解决你的问题,请参考以下文章

首次加载后以编程方式突出显示 tableview 中的第一行

UITableView 滚动后以编程方式创建的 UITableViewCell 未正确显示

iOS UITableView 在设置 TableHeaderView 后以编程方式覆盖自动布局约束

执行 JSON POST 时重新加载 TableView?

当我在 tableView 的最后一行单击“更多数据...”时,TableView 不会重新加载数据

获取异步 JSON 数据后重新加载 tableview