iOS开发- reloadData无效 (子线程更新UI错误)

http://www.2cto.com/kf/201410/342890.html


iOS开发- reloadData无效 (子线程更新UI错误)
2014-10-13       0  个评论       
收藏     我要投稿

今天在写一个聊天工具的时候遇到了一个问题。

注册的通知里面, 每当有其他用户发来消息的时候, UITableView 就要重新更新

?
1
cell.textLabel.textColor = [UIColor redColor];

使用红色标记cell名字来突出显示新消息。 (当然,, 这只是个demo, 效果比较渣。 正常情况应该是用户头像跳动或者显示新消息条数...)


可是我发现, 调用了这样的更新语句后, UITableVIew里面的数据并没有刷新。

?
1
2
3
4
- ( void )sessionUpdated:(NSNotification *)notification
{
       [myTableView reloadData];
}

设了下断点, 发现没有回调其Delegate的numberOfRowsInSection和CellForRow,所以导致界面没有更新。

这就费解了。

然后我手动的拖拽UI Tableview, 使其重绘, 发现数据更新了。 正常显示, 变红。

说明逻辑是没错的。 只是调用了reloadData后每效果。


之后就是百度学习了。

总结如下:

结论:

1、在子线程中是不能进行UI 更新的,而可以更新的结果只是一个幻像:因为子线程代码执行完毕了,又自动进入到了主线程,执行了子线程中的UI更新的函数栈,这中间的时间非常的短,就让大家误以为分线程可以更新UI。如果子线程一直在运行,则子线程中的UI更新的函数栈 主线程无法获知,即无法更新

2、只有极少数的UI能,因为开辟线程时会获取当前环境,如点击某个按钮,这个按钮响应的方法是开辟一个子线程,在子线程中对该按钮进行UI 更新是能及时的,如换标题,换背景图,但这没有任何意义


故而, 更新UI要在主线程中执行, 把上述代码改成这样(使用了GCD)

?
1
2
3
4
5
6
7
- ( void )sessionUpdated:(NSNotification *)notification
{
     dispatch_async(dispatch_get_main_queue(), ^{
                        [myTableView reloadData];
                        });
 
}

解决了问题。


-----
最终结果是在
- (void)requestPhotosData {
    NSString *remoteServerUrl = [FJConstantsUtil remoteServerUrl];
    NSString *listPath = [FJConstantsUtil commodityListPath];
    NSString *urlString = [remoteServerUrl stringByAppendingString:listPath];
    NSURL *url = [NSURL URLWithString:urlString];
    
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    request.HTTPMethod = @"GET";
    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        NSLog(@"Return from commodityList.");
        if (data == nil || error)
            return;
        NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:(NSJSONReadingMutableLeaves) error:nil];
        
        NSMutableArray *array = dict[@"data"];
        
        NSMutableArray *photosArray = [[NSMutableArray alloc] init];
        for (int i = 0; i < array.count; i++) {
            FJPhoto *photoVar = [[FJPhoto alloc] init];
            [photoVar setName:array[i][@"name"]];
            [photoVar setUrl:array[i][@"master_map"]];
            NSString *price = @"¥";
            NSString *priceAmount = [array[i][@"price"] stringValue];
            [photoVar setViewCount:([price stringByAppendingString:priceAmount])];
            [photosArray addObject:photoVar];
        }
        
//        [AppDelegate app].photos = photosArray;
        NSLog(@"Photos data is ready!");
        self.photos = photosArray;
        
        // This block code is in child thread.
        // So program have to update UI in ‘main thread’.
        dispatch_async(dispatch_get_main_queue(), ^{
            [self.tableView reloadData];
        });
    }];
    [task resume];
}



NSURLSessionDataTask<span style="font-family: 宋体; background-color: rgb(255, 255, 255);">会运行在子线程,</span><pre name="code" class="objc" style="color: rgb(51, 51, 51); font-size: 14px; line-height: 28px;">completionHandler:^()里的代码块也是运行在子线程。而在子线程中直接调用<pre name="code" class="objc" style="color: rgb(51, 51, 51); font-size: 14px; line-height: 28px;">[self.tableView reloadData]来更新UI是不行的。
于是,应该可以用GCD里的dispatch_async(queue, method)来在主线程中更新UI,即是
<pre name="code" class="objc" style="color: rgb(51, 51, 51); font-size: 14px; line-height: 28px;">dispatch_async(dispatch_get_main_queue(), ^{
            [self.tableView reloadData];
        });

解决问题。
详情见YimallsIos 项目的

FJPhotoListViewController.m

中的代码。

 
  
 
  
 
 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值