gpt4 book ai didi

ios - 多个NSUrlRequest以获取Web服务的不同页面以在TableView中加载更多数据

转载 作者:塔克拉玛干 更新时间:2023-11-02 09:18:08 24 4
gpt4 key购买 nike

我有一个简单的iPhone应用程序,它从rss feed解析数据(标题,图像等)并显示在tableview中。

viewDidLoad具有初始计数器值,该初始计数器值可到达feed的第一页并通过调用fetchEntriesNew方法加载到tableview中:

- (void)viewDidLoad
{
[super viewDidLoad];
counter = 1;
[self fetchEntriesNew:counter];

[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(dataSaved:)
name:@"DataSaved" object:nil];
}


- (void) fetchEntriesNew:(NSInteger )pageNumber
{
channel = [[TheFeedStore sharedStore] fetchWebService:pageNumber withCompletion:^(RSSChannel *obj, NSError *err){

if (!err) {
int currentItemCount = [[channel items] count];
channel = obj;
int newItemCount = [[channel items] count];
NSLog(@"Total Number Of Entries Are: %d", newItemCount);
counter = (newItemCount / 10) + 1;
NSLog(@"New Counter Should Be %d", counter);


int itemDelta = newItemCount - currentItemCount;
if (itemDelta > 0) {

NSMutableArray *rows = [NSMutableArray array];

for (int i = 0; i < itemDelta; i++) {
NSIndexPath *ip = [NSIndexPath indexPathForRow:i inSection:0];
[rows addObject:ip];
}
[[self tableView] insertRowsAtIndexPaths:rows withRowAnimation:UITableViewRowAnimationBottom];
[aiView stopAnimating];

}
}
}];
[[self tableView] reloadData];
}

当用户到达表格视图的底部时,我正在使用以下内容到达Feed的下一页,并在最先加载的第一页底部加载:
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
float endScrolling = scrollView.contentOffset.y + scrollView.frame.size.height;
if (endScrolling >= scrollView.contentSize.height)
{
NSLog(@"Scroll End Called");
NSLog(@"New Counter NOW is %d", counter);
[self fetchEntriesNew:counter];
}
}

UPDATE2:这是我无法解决的问题的更容易理解的描述:例如,在rss feed的每个页面中有10个条目。该应用程序启动,标题和其他标签立即加载,图像开始延迟加载并最终完成。到目前为止,一切都很好。用户滚动到底部,到达底部将使用滚动委托方法,计数器从1递增到2,告诉fetchEntriesNew方法到达rss feed的第二页。该程序将在先前获取的前10个条目的底部开始加载接下来的10个条目。这可以继续进行,并且每次用户滚动并到达底部时,程序将再获取10个条目,并且新行将放置在先前获取的行下方。到目前为止,一切都很好。

现在让我们说用户当前在第3页上,该页面已经完全加载了图像。由于第3页已完全加载,这意味着当前tableview中有30个条目。现在,用户滚动到底部,计数器增加,并且tableview开始在前30个条目底部的rss feed的第4页开始填充新行。标题会快速填充,从而建立行,并且在下载图像(尚未完全下载)时,用户迅速再次移至底部,而不是将第5页加载到第4页的底部,它将破坏第4页的内容当前正在下载中,并再次开始加载第4个。

它应该做的是,当用户到达表视图的底部时,无论上一页的图像是否处于下载中间,它都应保留下一页的标题等。

在我的项目中下载和保留数据没有问题,并且所有数据都在应用程序运行之间保留。

有人可以帮我指出正确的方向吗?提前致谢。

更新3:基于@Sergio的回答,这就是我所做的:

1)向archiveRootObject添加了另一个调用[NSKeyedArchiver archiveRootObject:channelCopy toFile:cachePath];在[channelCopy addItemsFromChannel:obj]之后;

在这一点上,它并没有一次又一次破坏并重新加载同一批,正是我想要的。但是,如果我滚动多次以到达下一页而没有完全加载上一页的图像,则它不会保留图像。

2)我不确定如何使用Bool(如他在回答中所述)。这就是我所做的:添加@property Bool myBool;在TheFeedStore中,对其进行合成,然后在新添加的archiveRootObject:channelCopy之后将其设置为NO,并在fetchEntries方法的最开始将其在ListViewController中设置为YES。没用

3)我也意识到我处理整个问题的方式是性能副手更好。虽然我不知道如何在缓存之外使用图像并将其作为缓存进行处理。您是否建议对图像使用单独的存档文件?

非常感谢所有为解决我的问题做出贡献的人们。

最佳答案

如果考虑使用this older question of yoursthe solution I proposed,则可以理解您的问题。

具体来说,关键点与您保留信息(RSS信息+图像)的方式有关,这是通过将整个channel归档到磁盘上的文件来实现的:

        [channelCopy addItemsFromChannel:obj];
[NSKeyedArchiver archiveRootObject:channelCopy toFile:pathOfCache];

现在,如果您查看 fetchEntriesNew:,那么您要做的第一件事就是销毁当前频道。如果在将通道持久存储到磁盘之前,在 发生这种情况,您将进入一种无穷循环。

我们了解到,您目前在图片下载结束时仍在坚持自己的频道(按照我的最初建议)。

您应该做的是在阅读提要之后并在开始下载图像之前保留频道(当然,您还应该在图像下载结束时保留频道)。

因此,如果您从我的老要点中摘录以下片段:
[connection setCompletionBlock:^(RSSChannel *obj, NSError *err) {

if (!err) {

[channelCopy addItemsFromChannel:obj];

// ADDED
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_group_wait(obj.imageDownloadGroup, DISPATCH_TIME_FOREVER);
[NSKeyedArchiver archiveRootObject:channelCopy toFile:cachePath];
});
}
block(channelCopy, err);

您应该做的是再添加一个archiveRootObject调用:
[connection setCompletionBlock:^(RSSChannel *obj, NSError *err) {

if (!err) {

[channelCopy addItemsFromChannel:obj];
[NSKeyedArchiver archiveRootObject:channelCopy toFile:cachePath];

// ADDED
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_group_wait(obj.imageDownloadGroup, DISPATCH_TIME_FOREVER);
[NSKeyedArchiver archiveRootObject:channelCopy toFile:cachePath];
});
}
block(channelCopy, err);

只要您滚动的速度不够快,就可以使一切正常,以便在读取提要(无图像)之前破坏频道。为了解决这个问题,您应该在调用TheFeedStore时将布尔值添加到设置为YESfetchWebService类中,并在执行新添加的archiveRootObject:channelCopy后立即重置。

这样可以解决您的问题。

我还要说,从设计/架构的角度来看,管理持久性的方式存在很大的问题。实际上,磁盘上只有一个文件,可以使用archiveRootObject原子地进行写入。从多线程的角度来看,此体系结构本质上是“危险的”,您还应该设计一种方法来避免对共享存储的并发访问没有破坏性的影响(例如:您将通道归档到磁盘上的第4页时间,因为第1页的图像已完全下载,因此您也尝试将它们也保存到同一文件中)。

图像处理的另一种方法是将图像存储在存档文件之外,并将其视为一种缓存。这样可以解决并发性问题,也可以避免每次为页面存档两次通道而导致的性能损失(第一次读取提要,之后进入图像时)。

希望这可以帮助。

更新:

在这一点上,它并没有一次又一次破坏并重新加载同一批,正是我想要的。但是,如果我滚动多次以到达下一页而没有完全加载上一页的图像,则它不会保留图像。

这恰恰是我的意思,您的体系结构(共享存档/并行访问)可能会导致问题。

您有几种选择:使用Core Data / sqlite;或者,更容易地将每个图像存储在自己的文件中。在后一种情况下,您可以执行以下操作:
  • 检索时,为每个图像分配一个文件名(可以是提要条目的ID或序号或其他),然后将图像数据存储在那里。
  • 在存档中存储图像的URL和应存储图像的文件名;
  • 当您需要访问图像时,您不会直接从已存档的字典中获取它。相反,您可以从中获取文件名,然后从磁盘中读取文件(如果有);
  • 此更改不会影响您当前的rss /图像检索的实现,而只会影响您保留图像并在需要时访问它们的方式(我的意思是,这似乎很简单)。

  • 2)我不确定如何使用Bool(如他在回答中所述)。
  • 在TheFeedStore中添加一个isDownloading bool;
  • 在执行YES之前,将其设置为fetchWebService:方法中的[connection start]
  • 第一次将提要归档后(您已经在执行此操作),在传递给连接对象的完成块中再次将
  • 设置为NO(再次在fetchWebService:中);
  • 首先,在您的scrollViewDidEndDecelerating:中添加
  • :
        if ([TheFeedStore sharedStore].isDownloading)
    return;

    这样您就不会在进行刷新时刷新rss feed。

  • 让我知道是否有帮助。

    新更新:

    让我概述一下如何处理在文件中存储图像。

    在您的RSSItem类中,定义:
    @property (nonatomic, readonly) UIImage *thumbnail;
    @property (nonatomic, strong) NSString *thumbFile;
    thumbFile是托管图像的本地文件的路径。获得图像URL(getFirstImageUrl)后,您可以获取它的MD5哈希值,并将其用作本地图像文件名:
    NSString* imageURLString = [self getFirstImageUrl:someString];
    ....
    self.thumbFile = [imageURLString MD5String];

    (MD5String是可以谷歌搜索的类别)。

    然后,在downloadThumbnails中,您将图像文件存储在本地:
        NSMutableData *tempData = [NSData dataWithContentsOfURL:finalUrl];
    [tempData writeToFile:[self cachedFileURLFromFileName:self.thumbFile] atomically:YES];
    [[NSNotificationCenter defaultCenter] postNotificationName:@"DataSaved" object:nil];

    现在,诀窍在于,当您访问thumbnail属性时,您将从文件中读取图像并返回它:
    - (UIImage *)thumbnail
    {
    NSData* d = [NSData dataWithContentsOfURL:[self cachedFileURLFromFileName:self.thumbFile]];
    return [[UIImage alloc] initWithData:d];
    }

    在此代码段中,cachedFileURLFromFileName:定义为:
    - (NSURL*)cachedFileURLFromFileName:(NSString*)filename {

    NSFileManager *fileManager = [[NSFileManager alloc] init];
    NSArray *fileArray = [fileManager URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask];

    NSURL* cacheURL = (NSURL*)[fileArray lastObject];
    if(cacheURL)
    {
    return [cacheURL URLByAppendingPathComponent:filename];
    }
    return nil;
    }

    当然,应保留thumbFile使其起作用。

    如您所见,这种方法非常容易实现。这不是一个优化的解决方案,只是使您的应用程序使用其当前架构的一种快速方法。

    为了完整起见,MD5String类别:
    @interface NSString (MD5)

    - (NSString *)MD5String;

    @end

    @implementation NSString (MD5)

    - (NSString *)MD5String {
    const char *cstr = [self UTF8String];
    unsigned char result[16];
    CC_MD5(cstr, strlen(cstr), result);

    return [NSString stringWithFormat:
    @"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
    result[0], result[1], result[2], result[3],
    result[4], result[5], result[6], result[7],
    result[8], result[9], result[10], result[11],
    result[12], result[13], result[14], result[15]
    ];
    }

    @end

    关于ios - 多个NSUrlRequest以获取Web服务的不同页面以在TableView中加载更多数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16143687/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com