有没有办法先加载文本字符串,然后使用 AFNetworking 加载图像?

Posted

技术标签:

【中文标题】有没有办法先加载文本字符串,然后使用 AFNetworking 加载图像?【英文标题】:Is there a way to load a text string first and then the image using AFNetworking? 【发布时间】:2013-10-29 19:45:50 【问题描述】:

我正在使用 AFNetworking 将 JSON 解析到我的应用程序(使用 Rails 作为我的后端)。现在我的应用程序非常慢,所以我正试图找出一种让它更流畅的方法。当我第一次加载应用程序时,它需要几秒钟才能填充(它显示导航项和一个白页,然后几秒钟后我的“帖子”出现)。

集合视图控制器

- (void)viewDidLoad

    [super viewDidLoad];

    self.upcomingReleases = [[NSMutableArray alloc] init];

    [self makeReleasesRequests];

    [self.collectionView registerClass:[ReleaseCell class] forCellWithReuseIdentifier:@"ReleaseCell"];


-(void)makeReleasesRequests

    NSURL *url = [NSURL URLWithString:@"http://www.soleresource.com/upcoming.json"];

    NSURLRequest *request = [NSURLRequest requestWithURL:url];

    AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];

    operation.responseSerializer = [AFJSONResponseSerializer serializer];

    [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) 

        NSLog(@"@");

        self.upcomingReleases = [responseObject objectForKey:@"upcoming_releases"];

        [self.collectionView reloadData];

     failure:nil];

    [operation start];


-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView

    return 1;


-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section

    return [self.upcomingReleases count];


#pragma mark - Show upcoming release shoe

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath 
    static NSString *identifier = @"Cell";

    ReleaseCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];

    NSDictionary *upcomingReleaseDictionary = [self.upcomingReleases objectAtIndex:indexPath.row];

    NSString *thumbURL = nil;

    cell.release_name.text = [NSString stringWithFormat:@"%@ — $%@",[upcomingReleaseDictionary objectForKey:@"release_name"], [upcomingReleaseDictionary objectForKey:@"release_price"]];

    if ([upcomingReleaseDictionary[@"images"] isKindOfClass:[NSArray class]] && [upcomingReleaseDictionary[@"images"] count]) 
        thumbURL = upcomingReleaseDictionary[@"images"][0][@"image_file"][@"image_file"][@"thumb"][@"url"];
        if (thumbURL)
        
            NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:thumbURL]];
            UIImage *image = [UIImage imageWithData:imageData];
            cell.thumb.image = image;
        
    
    else 
        cell.thumb.image = [UIImage imageNamed:@"air-jordan-5-fear.png"];
    

    return cell;

我的每个帖子都有一个文本字符串和一个图像。有没有办法加载文本以便它立即出现然后加载我的图像?或者是否有另一种方法可以加快我的应用加载速度(可能先加载某些帖子,然后再加载其余帖子 - 用户在向下滚动之前无法看到的帖子)。

谢谢。

【问题讨论】:

【参考方案1】:

当来自服务器时,您应该延迟和异步加载图像(不要阻塞主线程)。 (AFNetworking 已经在 UIImageView 上有缓存类别方法。(查看this 了解更多信息)

    if (thumbURL)
    
        [cell.thumb setImageWithURL:[NSURL URLWithString:thumbURL] placeholderImage:[UIImage imageNamed:@"air-jordan-5-fear.png"]];
    

编辑 -

确保将 UIKit+AFNetworking 文件夹拉到您的项目中,并将#import "UIKit+AFNetworking.h" 拉到您的 .m 文件中。可以找到下载完整 AFNetworking 的链接here 和特定于此问题的文档here。

【讨论】:

这段代码很糟糕,因为当图像完成加载时,单元格可能已被重用以显示不同的数据。我确信这段代码,如果你快速滚动,你会开始看到图像加载到错误的单元格上。 ChrisBedoya - 你能核实一下 Aaron 说了什么吗?我怀疑他可能是对的,而这种(替代方法)可能是可重复使用细胞的一种潜在错误方法。如果是这样,请告诉我,我会从我的答案中删除替代解决方案。感谢@AaronBrager 提出这个问题。 删除了替代方法。事实上,AFNetworking 本身有缓存 UIImageView 类别的方法,所以上面的答案现在应该很简单了。 我收到此错误:“NSString”没有可见的@interface 声明选择器“setImageWithURL:”。我正在使用 Collection View Controller 以防万一。 在这种情况下,您从另一个分支下载了 AFNetworking 文件,而不是从这个 - github.com/AFNetworking/AFNetworking【参考方案2】:

你的问题是这样的:

    if (thumbURL)
    
        NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:thumbURL]];
        UIImage *image = [UIImage imageWithData:imageData];
        cell.thumb.image = image;
    
    NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:thumbURL]];
    UIImage *image = [UIImage imageWithData:imageData];

您永远不应该在cellForItemAtIndexPath:获取数据。你应该只展示你已经拥有的东西。您的代码使其在下载缩略图之前不会返回任何单元格。您可以使用 Instruments 中的 Time Profiler 进行测量。

我假设thumb 是一个 UIImageView。试试这个:

if (thumb) 
    [thumb setImageWithURL:[NSURL URLWithString:@"http://i.imgur.com/r4uwx.jpg"]];

此方法也包含在 AFNetworking 中,它将下载图像,并在下载完成后在单元格中更新它。 Documentation and other similar methods are here.

【讨论】:

第一种方式是同步的;我推荐的一个是异步的。在此处阅读有关差异的更多信息:developer.apple.com/library/ios/DOCUMENTATION/General/… 我必须在代码中进行哪些更改才能异步加载图像? 使用我提供的建议。或者,在单元格滚动时开始下载您的图像,然后在图像完成后重新加载该行。 AFNetworking 方法正是为此目的而提供的。 我很困惑 - 你在问题中说你已经在使用 AFNetworking。 如果我将“if (thumbURL)”代码更改为您的代码,我会收到一条错误消息“未声明使用 thumb”,如果我将“thumb”更改为“thumbURL”,我会收到错误消息说“NSString 没有可见的@interface 声明选择器 setImageWithURL”。

以上是关于有没有办法先加载文本字符串,然后使用 AFNetworking 加载图像?的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法突出显示崇高文本或任何其他文本编辑器中的所有特殊重音字符?

有没有办法通过css慢慢地将字母添加到文本中? [关闭]

Spring Boot 应用 WAR 部署到 Resin 4:有没有办法先使用 app (WEB-INF/lib) 类加载器?

有没有办法先免费试用,然后一次性购买

在页面上使用文本字符串搜索功能,有没有办法让搜索忽略特定的 div?

有没有办法以编程方式在 TextView 中选择文本?