使用 GCD 异步加载指向服务器上图像的本地 JSON 文件
Load a local JSON file that points to images on a server asynchronously using GCD
我知道有很多关于这个主题的资源,但我的代码示例与这里的大多数示例的实现不同,我不确定如何解决这个问题。我正在尝试使用 Grand Central Dispatch 来解决它。似乎我已经尝试了所有方法,但是某些东西(我猜是正在下载的图像)阻塞了主线程。当我推送到包含 table 视图的视图控制器时,UI 锁定几秒钟,然后显示 table 视图。之后滚动很慢。
我对这些基本的 iOS 东西还是很陌生,因为我倾向于专注于游戏开发。我在尝试学习。也许更有经验的人可以指出我的错误?
所有 JSON 对象都存储在 NSDictionary 中。这是名为 Data.json 的数据文件:
{
"data" :
[
{
"user" : "3",
"username" : "John",
"avatar_url" : "http://api.mysite.com/images/avatar3.png",
"message" : "Bonjour?"
},
{
"user_id" : "4",
"username" : "Sam",
"avatar_url" : "http://api.mysite.com/images/avatar4.png",
"message" : "Yes, John."
},
{
"user_id" : "2",
"username" : "Becky",
"avatar_url" : "http://api.mysite.com/images/avatar2.png",
"message" : "I'm new here!"
},
]
}
ChatCell.h 中加载图像的方法:
- (void)loadWithData:(Data *)data {
self.userID = chatData.user_id;
// Where images are called from server
self.avatarImage.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:data.avatar_url]]];
self.usernameLabel.text = data.username;
self.messageTextView.text = data.message;
}
TableViewController.m:
@interface TableViewController ()
@property (nonatomic, strong) IBOutlet UITableView *tableView;
@property (nonatomic, strong) NSMutableArray *loadedChatData;
@end
- (void)viewDidLoad {
....
self.loadedChatData = [[NSMutableArray alloc] init];
[self loadJSONData];
}
- (void)loadJSONData {
//Here is my attempt using GCD dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"data" ofType:@"json"];
NSError *error = nil;
NSData *rawData = [NSData dataWithContentsOfFile:filePath options:NSDataReadingMappedIfSafe error:&error];
id JSONData = [NSJSONSerialization JSONObjectWithData:rawData options:NSJSONReadingAllowFragments error:&error];
[self.loadedChatData removeAllObjects];
if ([JSONData isKindOfClass:[NSDictionary class]])
{
NSDictionary *jsonDict = (NSDictionary *)JSONData;
NSArray *loadedArray = [jsonDict objectForKey:@"data"];
if ([loadedArray isKindOfClass:[NSArray class]])
{
for (NSDictionary *chatDict in loadedArray)
{
Data *data = [[Data alloc] init];
[data loadWithDictionary:chatDict];
[self.loadedChatData addObject:data];
}
}
}
// Updating UI on main queue?
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
});
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = @"ChatCell";
ChatCell *cell = (ChatCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:cellIdentifier owner:self options:nil];
cell = (ChatCell *)[nib objectAtIndex:0];
}
// I also tried using GCD's dispatch_async(dispatch_get_main_queue) within this method here with bad results
Data *data = [self.loadedChatData objectAtIndex:[indexPath row]];
[cell loadWithData:data];
return cell;
}
- (void)loadWithData:(Data *)data {
self.userID = chatData.user_id;
// Where images are called from server
self.usernameLabel.text = data.username;
self.messageTextView.text = data.message;
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
//Background Thread Functionality
UIImage *avatarImage = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:data.avatar_url]]];
dispatch_async(dispatch_get_main_queue(), ^(void){
//Run UI Updates
self.avatarImage.image = avatarImage;
});
});
}
我知道有很多关于这个主题的资源,但我的代码示例与这里的大多数示例的实现不同,我不确定如何解决这个问题。我正在尝试使用 Grand Central Dispatch 来解决它。似乎我已经尝试了所有方法,但是某些东西(我猜是正在下载的图像)阻塞了主线程。当我推送到包含 table 视图的视图控制器时,UI 锁定几秒钟,然后显示 table 视图。之后滚动很慢。
我对这些基本的 iOS 东西还是很陌生,因为我倾向于专注于游戏开发。我在尝试学习。也许更有经验的人可以指出我的错误?
所有 JSON 对象都存储在 NSDictionary 中。这是名为 Data.json 的数据文件:
{
"data" :
[
{
"user" : "3",
"username" : "John",
"avatar_url" : "http://api.mysite.com/images/avatar3.png",
"message" : "Bonjour?"
},
{
"user_id" : "4",
"username" : "Sam",
"avatar_url" : "http://api.mysite.com/images/avatar4.png",
"message" : "Yes, John."
},
{
"user_id" : "2",
"username" : "Becky",
"avatar_url" : "http://api.mysite.com/images/avatar2.png",
"message" : "I'm new here!"
},
]
}
ChatCell.h 中加载图像的方法:
- (void)loadWithData:(Data *)data {
self.userID = chatData.user_id;
// Where images are called from server
self.avatarImage.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:data.avatar_url]]];
self.usernameLabel.text = data.username;
self.messageTextView.text = data.message;
}
TableViewController.m:
@interface TableViewController ()
@property (nonatomic, strong) IBOutlet UITableView *tableView;
@property (nonatomic, strong) NSMutableArray *loadedChatData;
@end
- (void)viewDidLoad {
....
self.loadedChatData = [[NSMutableArray alloc] init];
[self loadJSONData];
}
- (void)loadJSONData {
//Here is my attempt using GCD dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"data" ofType:@"json"];
NSError *error = nil;
NSData *rawData = [NSData dataWithContentsOfFile:filePath options:NSDataReadingMappedIfSafe error:&error];
id JSONData = [NSJSONSerialization JSONObjectWithData:rawData options:NSJSONReadingAllowFragments error:&error];
[self.loadedChatData removeAllObjects];
if ([JSONData isKindOfClass:[NSDictionary class]])
{
NSDictionary *jsonDict = (NSDictionary *)JSONData;
NSArray *loadedArray = [jsonDict objectForKey:@"data"];
if ([loadedArray isKindOfClass:[NSArray class]])
{
for (NSDictionary *chatDict in loadedArray)
{
Data *data = [[Data alloc] init];
[data loadWithDictionary:chatDict];
[self.loadedChatData addObject:data];
}
}
}
// Updating UI on main queue?
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
});
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = @"ChatCell";
ChatCell *cell = (ChatCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:cellIdentifier owner:self options:nil];
cell = (ChatCell *)[nib objectAtIndex:0];
}
// I also tried using GCD's dispatch_async(dispatch_get_main_queue) within this method here with bad results
Data *data = [self.loadedChatData objectAtIndex:[indexPath row]];
[cell loadWithData:data];
return cell;
}
- (void)loadWithData:(Data *)data {
self.userID = chatData.user_id;
// Where images are called from server
self.usernameLabel.text = data.username;
self.messageTextView.text = data.message;
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
//Background Thread Functionality
UIImage *avatarImage = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:data.avatar_url]]];
dispatch_async(dispatch_get_main_queue(), ^(void){
//Run UI Updates
self.avatarImage.image = avatarImage;
});
});
}