在我滚动之前,数据不会加载到UITableView中。

时间:2021-07-29 00:57:29

I am trying to load parsed data in cells, but the problem is that it is happening synchronously and UitableView doesn't show until the data has finished loading. I tried to solve the problem by using performSelectorInBackground, but now data isn't loaded in the cells until I start scrolling. Here is my code:

我正在尝试在单元格中加载解析过的数据,但问题是它是同步进行的,直到数据完成加载之后,UitableView才会显示出来。我试图通过使用performSelectorInBackground来解决这个问题,但是现在直到我开始滚动数据才会加载到单元格中。这是我的代码:

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    [self performSelectorInBackground:@selector(fethchData) withObject:nil];


}


- (void)viewDidUnload
{
    [super viewDidUnload];
    // Release any retained subviews of the main view.
self.listData = nil;
    self.plot=nil;
}


-(void) fethchData

{
    NSError *error = nil;
    NSURL *url=[[NSURL alloc] initWithString:@"http://www.website.com/"];
    NSString *strin=[[NSString alloc] initWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];

    HTMLParser *parser = [[HTMLParser alloc] initWithString:strin error:&error];

    if (error) {
        NSLog(@"Error: %@", error);
        return;
    }

    listData =[[NSMutableArray alloc] init];
    plot=[[NSMutableArray alloc] init];

    HTMLNode *bodyNode = [parser body];
    NSArray *contentNodes = [bodyNode findChildTags:@"p"];


    for (HTMLNode *inputNode in contentNodes) {
            [plot addObject:[[inputNode allContents] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];    
        }


    NSArray *divNodes = [bodyNode findChildTags:@"h2"];

    for (HTMLNode *inputNode in divNodes) {

            [listData addObject:[[inputNode allContents] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];          

        }
    }


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

    static NSString *CellIdentifier = @"Cell";
    //here you check for PreCreated cell.
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
        cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;

    }

    //Fill the cells...  


    cell.textLabel.text = [listData objectAtIndex:indexPath.row];
    cell.textLabel.font = [UIFont boldSystemFontOfSize:14];
    cell.textLabel.numberOfLines=6; 
    cell.textLabel.textColor=[UIColor colorWithHue:0.7 saturation:1 brightness:0.4 alpha:1];


    cell.detailTextLabel.text=[plot objectAtIndex:indexPath.row];
    cell.detailTextLabel.font=[UIFont systemFontOfSize:11];
    cell.detailTextLabel.numberOfLines=6;

    return cell;


}

7 个解决方案

#1


125  

Put this somewhere after the data is loaded successfully:

在数据加载成功后,将其放在某处:

dispatch_async(dispatch_get_main_queue(), ^{
    [self.tableView reloadData];
});

This fix the problem of calling a GUI update while you're not in the main thread.

这解决了在不处于主线程时调用GUI更新的问题。

This code uses the GCD Technology from Apple to force the reload data function to run on main thread. Read more about Concurrency Programming Guide for more understanding (it's quite large field so that it's hard to explain in the comment) Anyway, it's not very recommended if you don't understand it well because it causes the program to crash some rare cases.

这段代码使用苹果的GCD技术来强制重载数据函数在主线程上运行。请阅读更多关于并发编程指南的内容,以获得更多的理解(它是一个非常大的字段,因此很难在注释中解释)。

#2


13  

For swift 3:

为迅速3:

DispatchQueue.main.async(execute: { () -> Void in
                self.tableView.reloadData()
            })

For swift 2:

为迅速2:

dispatch_async(dispatch_get_main_queue(), { () -> Void in
                self.tableView.reloadData()
            })

#3


9  

All you really need to do is any time you have an update to your back-end data, call

您真正需要做的就是在对后端数据进行更新时调用

[tableView reloadData];

Since this is happening synchronously, you should probably have a function like

由于这是同步发生的,所以您应该有一个类似的函数

-(void) updateTable
{
    [tableView reloadData];
}

and after adding the data in your download call

在下载调用中添加数据之后

[self performSelectorOnMainThread:@selector(updateTable) withObject:nil waitUntilDone:NO];

#4


2  

U can use [cell setNeedsDisplay]; for example:

可以使用[cell setNeedsDisplay];例如:

dispatch_async(dispatch_get_main_queue(), ^{
            [cell setNeedsDisplay];
            [cell.contentView addSubview:yourView];
        });

#5


1  

I was having the exact same problem! I wanted the UITableView to be fully populated before the view controller appeared. Envil's post gave me the information I needed, but my solution ended up being different.

我也有同样的问题!我希望UITableView在视图控制器出现之前被完全填充。Envil的文章给了我我所需要的信息,但我的解决方案却不一样。

Here's what I did (remodeled to fit the context of the question asker).

以下是我所做的(修改以适应提问者的上下文)。

- (void)viewDidLoad {
    [super viewDidLoad];
    [self performSelectorInBackground:@selector(fethchData) withObject:nil];
}

- (void)viewWillAppear {
    [tableView reloadData];
}

#6


1  

I had this problem and I was dealing with it all the day.

我有这个问题,我整天都在处理它。

I am using static cells and reloadData is causing the wrong loading, it displays only the visible cells and remove the others. What I noticed is that when I scrolled down (y in negative value) the cells where loaded correctly, so I wrote this code and it worked, even though I don't like to let it in this way.

我正在使用静态单元格,reloadData导致错误的加载,它只显示可见单元格,并删除其他单元格。我注意到,当我将单元格(y为负值)向下滚动时,正确地加载了这些单元格,所以我写了这段代码,它成功了,尽管我不喜欢这样。

Shoot if you find any better solution.

找到更好的解决办法就开枪。

-(void)reloadTableView{
        CGPoint point = self.tableSettings.tableView.contentOffset;
        [self.tableSettings.tableView reloadData];

        [UIView animateWithDuration:.001f animations:^{
            [self.tableSettings.tableView setContentOffset:CGPointMake(point.x, -10)];
        } completion:^(BOOL finished) {
            [UIView animateWithDuration:.001f animations:^{
                [self.tableSettings.tableView setContentOffset:point];
            } completion:^(BOOL finished) {

            }];
        }];
}

#7


0  

First, this semi-solved my related problem. I want to round corners of an image in a table cell. Dispatching asynchronously fixed the problem for some but not all of the images. Any ideas?

首先,这个半解决了我的相关问题。我想在表格单元格中圆角显示图像。异步调度解决了一些但不是所有映像的问题。什么好主意吗?

Second, I think you are supposed to avoid creating a strong reference cycle by using a closure capture list like this:

其次,我认为您应该通过使用这样的闭包捕获列表来避免创建一个强引用循环:

DispatchQueue.main.async(execute: { [weak weakSelf = self] () -> Void in
            weakSelf!.tableView.reloadData()
        })

See: https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html#//apple_ref/doc/uid/TP40014097-CH20-ID52

见:https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html / / apple_ref / doc / uid / TP40014097-CH20-ID52

#1


125  

Put this somewhere after the data is loaded successfully:

在数据加载成功后,将其放在某处:

dispatch_async(dispatch_get_main_queue(), ^{
    [self.tableView reloadData];
});

This fix the problem of calling a GUI update while you're not in the main thread.

这解决了在不处于主线程时调用GUI更新的问题。

This code uses the GCD Technology from Apple to force the reload data function to run on main thread. Read more about Concurrency Programming Guide for more understanding (it's quite large field so that it's hard to explain in the comment) Anyway, it's not very recommended if you don't understand it well because it causes the program to crash some rare cases.

这段代码使用苹果的GCD技术来强制重载数据函数在主线程上运行。请阅读更多关于并发编程指南的内容,以获得更多的理解(它是一个非常大的字段,因此很难在注释中解释)。

#2


13  

For swift 3:

为迅速3:

DispatchQueue.main.async(execute: { () -> Void in
                self.tableView.reloadData()
            })

For swift 2:

为迅速2:

dispatch_async(dispatch_get_main_queue(), { () -> Void in
                self.tableView.reloadData()
            })

#3


9  

All you really need to do is any time you have an update to your back-end data, call

您真正需要做的就是在对后端数据进行更新时调用

[tableView reloadData];

Since this is happening synchronously, you should probably have a function like

由于这是同步发生的,所以您应该有一个类似的函数

-(void) updateTable
{
    [tableView reloadData];
}

and after adding the data in your download call

在下载调用中添加数据之后

[self performSelectorOnMainThread:@selector(updateTable) withObject:nil waitUntilDone:NO];

#4


2  

U can use [cell setNeedsDisplay]; for example:

可以使用[cell setNeedsDisplay];例如:

dispatch_async(dispatch_get_main_queue(), ^{
            [cell setNeedsDisplay];
            [cell.contentView addSubview:yourView];
        });

#5


1  

I was having the exact same problem! I wanted the UITableView to be fully populated before the view controller appeared. Envil's post gave me the information I needed, but my solution ended up being different.

我也有同样的问题!我希望UITableView在视图控制器出现之前被完全填充。Envil的文章给了我我所需要的信息,但我的解决方案却不一样。

Here's what I did (remodeled to fit the context of the question asker).

以下是我所做的(修改以适应提问者的上下文)。

- (void)viewDidLoad {
    [super viewDidLoad];
    [self performSelectorInBackground:@selector(fethchData) withObject:nil];
}

- (void)viewWillAppear {
    [tableView reloadData];
}

#6


1  

I had this problem and I was dealing with it all the day.

我有这个问题,我整天都在处理它。

I am using static cells and reloadData is causing the wrong loading, it displays only the visible cells and remove the others. What I noticed is that when I scrolled down (y in negative value) the cells where loaded correctly, so I wrote this code and it worked, even though I don't like to let it in this way.

我正在使用静态单元格,reloadData导致错误的加载,它只显示可见单元格,并删除其他单元格。我注意到,当我将单元格(y为负值)向下滚动时,正确地加载了这些单元格,所以我写了这段代码,它成功了,尽管我不喜欢这样。

Shoot if you find any better solution.

找到更好的解决办法就开枪。

-(void)reloadTableView{
        CGPoint point = self.tableSettings.tableView.contentOffset;
        [self.tableSettings.tableView reloadData];

        [UIView animateWithDuration:.001f animations:^{
            [self.tableSettings.tableView setContentOffset:CGPointMake(point.x, -10)];
        } completion:^(BOOL finished) {
            [UIView animateWithDuration:.001f animations:^{
                [self.tableSettings.tableView setContentOffset:point];
            } completion:^(BOOL finished) {

            }];
        }];
}

#7


0  

First, this semi-solved my related problem. I want to round corners of an image in a table cell. Dispatching asynchronously fixed the problem for some but not all of the images. Any ideas?

首先,这个半解决了我的相关问题。我想在表格单元格中圆角显示图像。异步调度解决了一些但不是所有映像的问题。什么好主意吗?

Second, I think you are supposed to avoid creating a strong reference cycle by using a closure capture list like this:

其次,我认为您应该通过使用这样的闭包捕获列表来避免创建一个强引用循环:

DispatchQueue.main.async(execute: { [weak weakSelf = self] () -> Void in
            weakSelf!.tableView.reloadData()
        })

See: https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html#//apple_ref/doc/uid/TP40014097-CH20-ID52

见:https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html / / apple_ref / doc / uid / TP40014097-CH20-ID52