問(wèn)題描述
我成功地將博客文章中的縮略圖異步加載到我的 UITableView 中.
I am successfully loading thumbnail images from blog posts asynchronously into my UITableView.
我遇到的問(wèn)題是圖像只有在我點(diǎn)擊單元格或向下滾動(dòng)時(shí)才會(huì)出現(xiàn).
The issue I'm having is that the images only appear if I tap the cell OR if I scroll down.
當(dāng)我點(diǎn)擊單元格時(shí),圖像出現(xiàn)在左側(cè),將標(biāo)題和副標(biāo)題推到右側(cè).
When I tap the cell, the image appears on the left, pushing the Title and Subtitle to the right.
當(dāng)我向下滾動(dòng)時(shí),圖像會(huì)顯示在單元格中應(yīng)顯示的位置.
When I scroll down, the images appear where they should in the cells as they are revealed.
這是我的代碼(我正在使用 AFNetworking):
Here's my code (I'm using AFNetworking):
#import "UIImageView+AFNetworking.h"
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return posts.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
NSDictionary *post = [posts objectAtIndex:indexPath.row];
NSString *postpictureUrl = [post objectForKey:@"picture"];
[cell.imageView setImageWithURL:[NSURL URLWithString:postpictureUrl]];
cell.textLabel.text = [post objectForKey:@"post_text"];
cell.detailTextLabel.text = [post objectForKey:@"post_author_name"];
return cell;
}
我在 iPhone 6.0 模擬器、XCode 4.5、OSX MtLion 中看到了這一點(diǎn).
I am seeing this in the iPhone 6.0 simulator, XCode 4.5, OSX MtLion.
任何想法為什么圖像沒(méi)有繪制在初始屏幕上?
Any ideas why the images are not drawn on the initial screen?
推薦答案
在混合 asynch 和 table 時(shí)要注意的是 asynch 在未來(lái)未知的時(shí)間結(jié)束,可能是在單元格滾動(dòng)離開(kāi)之后、刪除、重復(fù)使用等.
The thing you want to be aware of when mixing asynch and tables is that the asynch finishes at an unknown time in the future, possibly after the cell is scrolled away, removed, reused, etc.
此外,如果該單元格被滾動(dòng)離開(kāi),則從網(wǎng)絡(luò)中提取的圖像會(huì)丟失.不確定 AFNetworking 是否為您緩存,但最好不要假設(shè).這是使用本地網(wǎng)絡(luò)的解決方案:
Also, the image that gets pulled from the web is lost if that cell is scrolled away. Not sure if AFNetworking caches for you, but it might be better to not assume. Here's a solution using native networking:
// ...
NSDictionary *post = [posts objectAtIndex:indexPath.row];
NSString *postpictureUrl = [post objectForKey:@"picture"];
// find a place in your model, or add one, to cache an actual downloaded image
UIImage *postImage = [post objectForKey:@"picture_image"];
if (postImage) {
cell.imageView.image = postImage; // this is the best scenario: cached image
} else {
// notice how we don't pass the cell - we don't trust its value past this turn of the run loop
[self asynchLoad:postpictureUrl forIndexPath:indexPath];
cell.imageView.image = [UIImage imageNamed:@"default"];
}
// ...
現(xiàn)在,沒(méi)有任何第三方幫助的嚴(yán)肅異步加載
Now, a no-nonsense asynch load without any 3rd party help
- (void)asynchLoad:(NSString *)urlString forIndexPath:(NSIndexPath *)indexPath {
NSURL *url = [NSURL urlWithString:urlString];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (!error) {
// create the image
UIImage *image = [UIImage imageWithData:data];
// cache the image
NSDictionary *post = [posts objectAtIndex:indexPath.row];
[post setObject:image forKey:@"picture_image"];
// important part - we make no assumption about the state of the table at this point
// find out if our original index path is visible, then update it, taking
// advantage of the cached image (and a bonus option row animation)
NSArray *visiblePaths = [self.tableView indexPathsForVisibleRows];
if ([visiblePaths containsObject:indexPath]) {
NSArray *indexPaths = [NSArray arrayWithObject:indexPath];
[self.tableView reloadRowsAtIndexPaths:indexPaths withRowAnimation: UITableViewRowAnimationFade];
// because we cached the image, cellForRow... will see it and run fast
}
}
}];
}
為此,帖子應(yīng)創(chuàng)建為 NSMutableDictionary...
For this to work, the posts should be created as NSMutableDictionary...
// someplace in your code you add a post to the posts array. do this instead.
NSDictionary *postData = // however you get a new post
[posts addObject:[NSMutableDictionary dictionaryWithDictionary:postData]];
或者,如果很難直接更改帖子模型,您可以設(shè)置另一個(gè)結(jié)構(gòu)來(lái)緩存下載的圖像.由 url 字符串鍵入的可變字典是一個(gè)很好的結(jié)構(gòu):
Alternatively, if it's hard to change the posts model directly, you can setup another structure to cache the downloaded images. A mutable dictionary keyed by the url strings is a good structure to use:
@property (nonatomic,strong) NSMutableDictionary *imageCache;
@synthesize imageCache=_imageCache;
// lazy init on the getter...
- (NSMutableDictionary *)imageCache {
if (!_imageCache) {
_imageCache = [NSMutableDictionary dictionary];
}
return _imageCache;
}
現(xiàn)在,在配置單元格的時(shí)候,通過(guò)查看緩存來(lái)查看是否有緩存的圖片...
Now, when configuring the cell, see if there's a cached image by checking the cache...
// change to the cellForRowAtIndexPath method
NSString *postpictureUrl = [post objectForKey:@"picture"];
UIImage *postImage = [self.imageCache valueForKey:postpictureUrl];
一旦下載了圖片,緩存它...
And once an image is downloaded, cache it...
// change to the asynchLoad: method I suggested
UIImage *image = [UIImage imageWithData:data];
[self.imageCache setValue:image forKey:urlString];
這篇關(guān)于異步下載的圖像僅在點(diǎn)擊或滾動(dòng)后出現(xiàn)在 UITableView 中的文章就介紹到這了,希望我們推薦的答案對(duì)大家有所幫助,也希望大家多多支持html5模板網(wǎng)!