我正在尝试创建一个简单的 Twitter 客户端,延迟加载 Twitter 图像。我可以在 UITableView 中获取和显示推文,但我无法加载图像。
这就是我得到的,文本和用户名正确加载但没有图像:
我认为问题可能出在此方法中,该方法在图像加载后由委托调用并应在表格视图单元格中显示图像:
// Called by ImageDownloader when image is ready to be displayed
- (void)imageDidLoad:(NSString *)downloadedImageUrl downloadedImage:(UIImage *)downloadedImage
{
for (Tweet *tweet in self.tweets) {
if (tweet.userProfileImageUrl == downloadedImageUrl) {
tweet.userProfileImage = downloadedImage;
UITableViewCell *tweetCell = [self.tableView cellForRowAtIndexPath:tweet.uiTableViewCellIndexPath];
tweetCell.imageView.image = downloadedImage;
}
}
}
但我在下面粘贴了更多我的代码,以确保......
我为我的推文定义了一个简单的类:
@interface Tweet : NSObject
{
NSString *userName;
NSString *text;
NSString *userProfileImageUrl;
UIImage *userProfileImage;
NSIndexPath *uiTableViewCellIndexPath;
}
@property (nonatomic, retain) NSString *userName;
@property (nonatomic, retain) NSString *text;
@property (nonatomic, retain) NSString *userProfileImageUrl;
@property (nonatomic, retain) UIImage *userProfileImage;
@property (nonatomic, retain) NSIndexPath *uiTableViewCellIndexPath;
@end
我还实现了一个简单的图像下载器类:
@protocol ImageDownloaderDelegate
- (void)imageDidLoad:(NSString *)downloadedImageUrl downloadedImage:(UIImage *)downloadedImage;
@end
@interface ImageDownloader : NSObject
{
NSString *imageUrl;
UIImage *downloadedImage;
id <ImageDownloaderDelegate> __unsafe_unretained delegate;
NSMutableData *activeDownload;
NSURLConnection *imageConnection;
}
@property (nonatomic, retain) NSString *imageUrl;
@property (nonatomic, retain) UIImage *downloadedImage;
@property (unsafe_unretained) id <ImageDownloaderDelegate> delegate;
@property (nonatomic, retain) NSMutableData *activeDownload;
@property (nonatomic, retain) NSURLConnection *imageConnection;
- (void)startDownload;
- (void)cancelDownload;
@end
有了这个实现:
#import "ImageDownloader.h"
#define kImageWidth 48
#define kImageHeight 48
@implementation ImageDownloader
@synthesize imageUrl;
@synthesize downloadedImage;
@synthesize delegate;
@synthesize activeDownload;
@synthesize imageConnection;
#pragma mark
- (void)startDownload
{
self.activeDownload = [NSMutableData data];
self.imageConnection = [[NSURLConnection alloc] initWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:self.imageUrl]] delegate:self];
}
- (void)cancelDownload
{
[self.imageConnection cancel];
self.imageConnection = nil;
self.activeDownload = nil;
}
#pragma mark -
#pragma mark Download support (NSURLConnectionDelegate)
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
// Clear the activeDownload property to allow later attempts
self.activeDownload = nil;
// Release the connection now that it's finished
self.imageConnection = nil;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// Set userProfileImage and clear temporary data/image
UIImage *image = [[UIImage alloc] initWithData:self.activeDownload];
if (image.size.width != kImageWidth || image.size.height != kImageHeight) {
CGSize itemSize = CGSizeMake(kImageWidth, kImageHeight);
UIGraphicsBeginImageContext(itemSize);
CGRect imageRect = CGRectMake(0.0, 0.0, itemSize.width, itemSize.height);
[image drawInRect:imageRect];
self.downloadedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
} else {
self.downloadedImage = image;
}
self.activeDownload = nil;
// Release the connection now that it's finished
self.imageConnection = nil;
// Call our delegate and tell it that our image is ready for display
[delegate imageDidLoad:self.imageUrl downloadedImage:self.downloadedImage];
}
@end
在我的主控制器中,我加载了推文:
// Fetch the Twitter timeline and assigns tweets to the tweets property
- (void)fetchTweets
{
self.tweets = [[NSMutableArray alloc] init];
NSString *userTimelineUrl = @"https://api.twitter.com/1/statuses/user_timeline.json?include_entities=true&include_rts=true&screen_name=richardknop&count=25";
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:userTimelineUrl]];
NSError *error;
NSArray *tweetJsonObjects = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
for (NSUInteger i = 0; i < [tweetJsonObjects count]; i++) {
Tweet *tweet = [[Tweet alloc] init];
tweet.userName = [[[tweetJsonObjects objectAtIndex:i] objectForKey:@"user"] objectForKey:@"name"];
NSString * textString = [[tweetJsonObjects objectAtIndex:i] objectForKey:@"text"];
tweet.text = textString;
tweet.userProfileImageUrl = [[[tweetJsonObjects objectAtIndex:i] objectForKey:@"user"] objectForKey:@"profile_image_url"];
[self.tweets addObject:tweet];
}
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
});
}
这是我加载表格视图内容的方式:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
int count = [self.tweets count];
return count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = @"TweetCell";
UITableViewCell * tweetCell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (tweetCell == nil) {
tweetCell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
}
if ([self.tweets count] > 0) {
Tweet *tweet = [self.tweets objectAtIndex:indexPath.row];
tweet.uiTableViewCellIndexPath = indexPath;
tweetCell.textLabel.text = tweet.text;
tweetCell.detailTextLabel.text = tweet.userName;
// Only load cached images; defer new downloads until scrolling ends
if (!tweet.userProfileImage) {
if (self.tableView.dragging == NO && self.tableView.decelerating == NO) {
[self startImageDownload:tweet.userProfileImageUrl];
}
// If a download is deferred or in progress, return a placeholder image
tweetCell.imageView.image = [UIImage imageNamed:@"Placeholder.png"];
} else {
tweetCell.imageView.image = tweet.userProfileImage;
}
}
return tweetCell;
}
如果推文图像,此方法开始下载:
- (void)startImageDownload:(NSString *)userProfileImageUrl
{
BOOL downloadAlreadyInProgress = NO;
for (ImageDownloader *storedImageDownloader in self.imageDownloadsInProgress) {
if (storedImageDownloader.imageUrl == userProfileImageUrl) {
downloadAlreadyInProgress = YES;
}
}
if (downloadAlreadyInProgress == NO) {
ImageDownloader *imageDownloader = [[ImageDownloader alloc] init];
imageDownloader.imageUrl = userProfileImageUrl;
imageDownloader.delegate = self;
[self.imageDownloadsInProgress addObject:imageDownloader];
[imageDownloader startDownload];
}
}