以块方式读取多个数据IOS
Read multiple data in block method IOS
我正在尝试通过这种方式从数据库中下载一系列图片:
- (void)dowloadAdditionalFileDataForFileObjectId:(NSString *)assignedObjectId andUserID:(NSString *)userID completition:(void (^) (BOOL success))block {
if (userID != nil && assignedObjectId != nil) {
PFQuery *query = [PFQuery queryWithClassName:@"AdditionalFileData"];
[query whereKey:@"fileAssignedObjectId" equalTo:assignedObjectId];
[query whereKey:@"userID" equalTo:userID];
[query findObjectsInBackgroundWithBlock: ^(NSArray *objects, NSError *error) {
if (!error) {
PFObject *object = [objects firstObject];
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);
__block UIImage *image1;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
if (object[@"image1"] != nil)
[self downloadDataForObject:object withParameter:@"image1" andCallback:^(NSData *data) {
image1 = [UIImage imageWithData:data];
dispatch_group_leave(group);
}];
});
__block UIImage *image2;
if (object[@"image2"] != nil)
[self downloadDataForObject:object withParameter:@"image2" andCallback:^(NSData *data) {
image2 = [UIImage imageWithData:data];
}];
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
[DBManager storeAdditionalDataForFileWithObjectId:assignedObjectId forUserID:userID withImage1:image1 andImage2:image2 andImage3:image3 ...] local:NO completition: ^(BOOL finished) {
if (finished)
block(YES);
else
block(NO);
}];
}
else
block(NO);
}];
}
else
block(NO);
}
- (void)downloadDataForObject:(PFObject *)object withParameter:(NSString *)parameter andCallback:(void (^)(NSData *data))callback{
[object[[NSString stringWithFormat:@"%@", parameter]] getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
callback(data);
}];
}
如果我只是写:
image1 = [UIImage imageWithData:[... getData]];
然后一切正常,但是用户界面被阻塞,直到过程结束。
我想要一些系统,以便在后台下载数据。由于我的图片可能多于 2 张,嵌套块不会解决任何问题。
我尝试使用您在上面看到的代码。
有什么建议吗?
编辑:
忘了明确提到所有下载方法,例如
getDataInBackground
调用 Parse SDK (Parse.com)。
杂项数据解决方案:
如果您愿意,可以使用复制一些 SDWebimages 行为的下载管理器。另一种选择是 AFNetworking,它可以帮助您以更简单的方式异步获取文件,并且它们声明有缓存。它们都可以在 GitHub.
找到
仅图片解决方案:
您可以使用像 SDWebImages 这样的库来做到这一点。这个库基本上为 UIImageView 提供了一个类别,支持来自网络的远程图像。所有下载都在后台完成。它还保证您不会因为本地缓存而一遍又一遍地下载相同的图像。
[UIImage imageWithData:]
这将阻塞直到完成:它不是异步操作。
您似乎在试图解决这个问题时陷入了困境,并且您的代码因此变得非常复杂,这可能对您没有太大帮助。
如果 getDataInBackgroundWithBlock
正在做我想象的事情,它会在数据可用时立即调用完成块。删除调度组并使用回调:让它们在共享方法中更新状态,一旦所有数据可用(即所有块都已触发)调用
storeAdditionalDataForFileWithObjectId
如您所知数据可用。
尽管我认为您只需要在 PFQuery 上使用 "includeKey" 方法,完整的查询应该看起来更像(参见 includeKey 部分):
@interface MyParseObject:PFObject<PFSubclassing>
@property (retain) NSArray *images;
@end
@implementation MyParseObject
@dynamic images;
int completed;
void (^loadingImagesComplete)(BOOL success);
- (void)loadImagesWithItemCompletion:(void(^)(UIImage *relatedImage))imageCompleted andCompletion:(void(^)(BOOL success))processCompleted{
loadingImagesComplete = processCompleted;
completed = 0;
PFQuery *queryForItems = [PFQuery queryWithClassName:@"yourClassName"];
[queryForItems whereKey:@"yourKey" equalTo:@"yourValue"];
//This is the part I THINK YOURE LOOKING FOR
//THE QUERY IN YOUR QUESTION WOULD INCLUDE
//**[query includeKey:@"image1"]**;
//**[query includeKey:@"image2"]**;
[queryForItems includeKey:@"images"];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for(PFFile *imageFile in self.images){
if (!imageFile.isDataAvailable){
[imageFile getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
imageCompleted([UIImage imageWithData:data]); //maybe callback to main queue for this
completed++;
[self checkLoadingCompleted];
}];
}else{
imageCompleted([UIImage imageWithData:[imageFile getData]]);
completed++;
[self checkLoadingCompleted];
}
}
});
}
- (void)checkLoadingCompleted{
if(completed == self.images.count){
loadingImagesComplete(YES);// the block called here should make reference to MainQueue when updating any UI Elements
}
}
@end
@implementation SomeOtherClass
- (void)loadImages{
[self.myParseObject loadImagesWithItemCompletion:^(UIImage *relatedImage) {
//this will fire every time an image is done downloading
} andCompletion:^(BOOL success) {
//this will fire after all images are done downloading
}];
}
@end
您可以为此使用螺栓库,parse 已经包括在内。将使代码更简单,下面的示例可以轻松扩展为超过 2 个图像或其他文件。
// do your query
PFObject *object = [objects firstObject];
PFFile *file1 = object[@"image1"];
PFFile *file2 = object[@"image2"];
BFTask* task1 = [file1 getDataInBackground];
BFTask* task2 = [file2 getDataInBackground];
[BFTask taskForCompletionOfAllTasks:@[task1, task2]] continueWithBlock:^id(BFTask *task) {
if(!task.error){
UIImage* image1 = [UIImage imageWithData:task1.result];
UIImage* image2 = [UIImage imageWithData:task2.result];
// do your thing with the images
}
return nil;
}];
使用名为 Superman 的很棒的 Github 库。
#import "Superman.h"
然后使用下面的方法
Superman *downloadImages = [[Superman alloc] init];
[downloadImages setDownloads: @"http://...../image1.png", @"http://...../image2.png", @"http://...../image3.png", @"http://...../image4.png", nil];
我正在尝试通过这种方式从数据库中下载一系列图片:
- (void)dowloadAdditionalFileDataForFileObjectId:(NSString *)assignedObjectId andUserID:(NSString *)userID completition:(void (^) (BOOL success))block {
if (userID != nil && assignedObjectId != nil) {
PFQuery *query = [PFQuery queryWithClassName:@"AdditionalFileData"];
[query whereKey:@"fileAssignedObjectId" equalTo:assignedObjectId];
[query whereKey:@"userID" equalTo:userID];
[query findObjectsInBackgroundWithBlock: ^(NSArray *objects, NSError *error) {
if (!error) {
PFObject *object = [objects firstObject];
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);
__block UIImage *image1;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
if (object[@"image1"] != nil)
[self downloadDataForObject:object withParameter:@"image1" andCallback:^(NSData *data) {
image1 = [UIImage imageWithData:data];
dispatch_group_leave(group);
}];
});
__block UIImage *image2;
if (object[@"image2"] != nil)
[self downloadDataForObject:object withParameter:@"image2" andCallback:^(NSData *data) {
image2 = [UIImage imageWithData:data];
}];
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
[DBManager storeAdditionalDataForFileWithObjectId:assignedObjectId forUserID:userID withImage1:image1 andImage2:image2 andImage3:image3 ...] local:NO completition: ^(BOOL finished) {
if (finished)
block(YES);
else
block(NO);
}];
}
else
block(NO);
}];
}
else
block(NO);
}
- (void)downloadDataForObject:(PFObject *)object withParameter:(NSString *)parameter andCallback:(void (^)(NSData *data))callback{
[object[[NSString stringWithFormat:@"%@", parameter]] getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
callback(data);
}];
}
如果我只是写:
image1 = [UIImage imageWithData:[... getData]];
然后一切正常,但是用户界面被阻塞,直到过程结束。
我想要一些系统,以便在后台下载数据。由于我的图片可能多于 2 张,嵌套块不会解决任何问题。
我尝试使用您在上面看到的代码。
有什么建议吗?
编辑:
忘了明确提到所有下载方法,例如
getDataInBackground
调用 Parse SDK (Parse.com)。
杂项数据解决方案:
如果您愿意,可以使用复制一些 SDWebimages 行为的下载管理器。另一种选择是 AFNetworking,它可以帮助您以更简单的方式异步获取文件,并且它们声明有缓存。它们都可以在 GitHub.
找到仅图片解决方案:
您可以使用像 SDWebImages 这样的库来做到这一点。这个库基本上为 UIImageView 提供了一个类别,支持来自网络的远程图像。所有下载都在后台完成。它还保证您不会因为本地缓存而一遍又一遍地下载相同的图像。
[UIImage imageWithData:]
这将阻塞直到完成:它不是异步操作。
您似乎在试图解决这个问题时陷入了困境,并且您的代码因此变得非常复杂,这可能对您没有太大帮助。
如果 getDataInBackgroundWithBlock
正在做我想象的事情,它会在数据可用时立即调用完成块。删除调度组并使用回调:让它们在共享方法中更新状态,一旦所有数据可用(即所有块都已触发)调用
storeAdditionalDataForFileWithObjectId
如您所知数据可用。
尽管我认为您只需要在 PFQuery 上使用 "includeKey" 方法,完整的查询应该看起来更像(参见 includeKey 部分):
@interface MyParseObject:PFObject<PFSubclassing>
@property (retain) NSArray *images;
@end
@implementation MyParseObject
@dynamic images;
int completed;
void (^loadingImagesComplete)(BOOL success);
- (void)loadImagesWithItemCompletion:(void(^)(UIImage *relatedImage))imageCompleted andCompletion:(void(^)(BOOL success))processCompleted{
loadingImagesComplete = processCompleted;
completed = 0;
PFQuery *queryForItems = [PFQuery queryWithClassName:@"yourClassName"];
[queryForItems whereKey:@"yourKey" equalTo:@"yourValue"];
//This is the part I THINK YOURE LOOKING FOR
//THE QUERY IN YOUR QUESTION WOULD INCLUDE
//**[query includeKey:@"image1"]**;
//**[query includeKey:@"image2"]**;
[queryForItems includeKey:@"images"];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for(PFFile *imageFile in self.images){
if (!imageFile.isDataAvailable){
[imageFile getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
imageCompleted([UIImage imageWithData:data]); //maybe callback to main queue for this
completed++;
[self checkLoadingCompleted];
}];
}else{
imageCompleted([UIImage imageWithData:[imageFile getData]]);
completed++;
[self checkLoadingCompleted];
}
}
});
}
- (void)checkLoadingCompleted{
if(completed == self.images.count){
loadingImagesComplete(YES);// the block called here should make reference to MainQueue when updating any UI Elements
}
}
@end
@implementation SomeOtherClass
- (void)loadImages{
[self.myParseObject loadImagesWithItemCompletion:^(UIImage *relatedImage) {
//this will fire every time an image is done downloading
} andCompletion:^(BOOL success) {
//this will fire after all images are done downloading
}];
}
@end
您可以为此使用螺栓库,parse 已经包括在内。将使代码更简单,下面的示例可以轻松扩展为超过 2 个图像或其他文件。
// do your query
PFObject *object = [objects firstObject];
PFFile *file1 = object[@"image1"];
PFFile *file2 = object[@"image2"];
BFTask* task1 = [file1 getDataInBackground];
BFTask* task2 = [file2 getDataInBackground];
[BFTask taskForCompletionOfAllTasks:@[task1, task2]] continueWithBlock:^id(BFTask *task) {
if(!task.error){
UIImage* image1 = [UIImage imageWithData:task1.result];
UIImage* image2 = [UIImage imageWithData:task2.result];
// do your thing with the images
}
return nil;
}];
使用名为 Superman 的很棒的 Github 库。
#import "Superman.h"
然后使用下面的方法
Superman *downloadImages = [[Superman alloc] init];
[downloadImages setDownloads: @"http://...../image1.png", @"http://...../image2.png", @"http://...../image3.png", @"http://...../image4.png", nil];