上一篇:我正试图在相机胶卷中获取照片数量,我开始使用积木但是遇到了一些困难。
现在: 这是我更新的代码,我正在使用异步行为,但在我的块有机会完成之前返回一个值。
#import "CoverViewController.h"
#import <AssetsLibrary/AssetsLibrary.h>
@interface CoverViewController () <UITextFieldDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>
@property(nonatomic, weak) IBOutlet UICollectionView *collectionView;
@property (assign) NSUInteger numberOfPhotos;
@end
@implementation CoverViewController
@synthesize CoverView;
- (void)viewWillAppear:(BOOL)animated
{
NSLog(@"viewWillAppear");
[self beginLoadingPhotoInfo];
}
//Photo collection info
- (void)beginLoadingPhotoInfo {
NSLog(@"loaded beginloadingphotoinfo");
__weak CoverViewController *__self = self;
[self PhotoCount:^(NSUInteger photoCount) {
__self.numberOfPhotos = photoCount;
}];
//[__self.CoverView reloadData];
}
- (void)PhotoCount:(void(^)(NSUInteger))completionBlock {
NSLog(@"photo count start");
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
__block NSInteger result = 0;
void (^assetGroupEnumerator)(ALAssetsGroup *, BOOL *) = ^(ALAssetsGroup *group, BOOL *stop){
if(group != nil) {
NSLog(@"if");
result += [group numberOfAssets];
NSLog(@"enum: %d", result);
}
else {
NSLog(@"else");
//nil means we are done with enumeration
if (completionBlock) {
completionBlock(result);
}
}
};
[library enumerateGroupsWithTypes: ALAssetsGroupSavedPhotos
usingBlock:assetGroupEnumerator
failureBlock:^(NSError *error) {NSLog(@"Problems");}
];
NSLog(@"result: %u", result);
}
// Layout of collection
//Number of cells in collection
- (NSInteger)collectionView:(UICollectionView *)view numberOfItemsInSection:(NSInteger)section {
NSLog(@"returned number: %d", self.numberOfPhotos);
return self.numberOfPhotos;
}
@end
我添加了与coverviewcontroller.h文件相关的所有内容,但代码似乎是在块完成之前加载的。这是我尝试找到错误,它显示photoCount在我的块完成之前返回0。
2013-07-27 21:16:00.986 slidr[1523:c07] viewWillAppear
2013-07-27 21:16:00.987 slidr[1523:c07] loaded beginloadingphotoinfo
2013-07-27 21:16:00.987 slidr[1523:c07] photo count start
2013-07-27 21:16:00.988 slidr[1523:c07] result: 0
2013-07-27 21:16:00.989 slidr[1523:c07] returned number: 0
2013-07-27 21:16:01.012 slidr[1523:c07] if
2013-07-27 21:16:01.013 slidr[1523:c07] enum: 3
2013-07-27 21:16:01.014 slidr[1523:c07] else
任何想法?
答案 0 :(得分:1)
您正在混合和匹配同步和异步方法。有两种可能的方法。
通过传递完成块使您的photoCount
方法异步返回。
- (void)PhotoCount:(void(^)(NSUInteger))completionBlock {
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
__block NSInteger result = 0;
void (^assetGroupEnumerator)(ALAssetsGroup *, BOOL *) = ^(ALAssetsGroup *group, BOOL *stop){
if(group != nil) {
if([[group valueForProperty:ALAssetPropertyType] isEqualToString:ALAssetTypePhoto]) {
result += [group numberOfAssets];
}
} else {
// nil group signals we're done with enumeration
if (completionBlock) {
completionBlock(result);
}
}
};
[library enumerateGroupsWithTypes: ALAssetsGroupSavedPhotos
usingBlock:assetGroupEnumerator
failureBlock:^(NSError *error) {NSLog(@"Problems");}
];
}
或
阻止当前线程,直到操作完成。这在交互式用户应用程序中通常不是一个好主意。如果你这样做,你应该重新考虑这部分应用程序的结构:
- (NSUInteger)PhotoCount {
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
__block NSInteger result = 0;
dispatch_semaphore_t blockSemaphore = dispatch_semaphore_create(0);
void (^assetGroupEnumerator)(ALAssetsGroup *, BOOL *) = ^(ALAssetsGroup *group, BOOL *stop){
if(group != nil) {
if([[group valueForProperty:ALAssetPropertyType] isEqualToString:ALAssetTypePhoto]) {
result += [group numberOfAssets];
}
} else {
// nil group signals we're done with enumeration
dispatch_semaphore_signal(blockSemaphore);
}
};
[library enumerateGroupsWithTypes: ALAssetsGroupSavedPhotos
usingBlock:assetGroupEnumerator
failureBlock:^(NSError *error) {NSLog(@"Problems");}
];
dispatch_semaphore_wait(blockSemaphore, DISPATCH_TIME_FOREVER);
NSLog(@"%u", result);
return result;
}
您还以我完全不理解的方式使用resultBlock
变量,所以我从答案中省略了它。
为了清楚起见,我不会选择选项2.它会导致应用程序的响应性显着延迟,特别是如果你在主线程上调用它,特别是如果用户有一个大的资产库。
使用块进行编程的一个好处是,您可以推迟工作,直到获得完成工作所需的所有信息。据推测,你将改变一些UI元素以响应这个数字的结果。将代码放在您传递给上述方法的完成块中。或者更好的是,将代码放入一个然后从块中调用的方法。
要继续使用异步方法,在集合视图控制器中,您需要一个预先计算此数字的方法,可能是在控制器加载时:
@property (assign) NSUInteger numberOfPhotos;
- (void)beginLoadingCollectionInformation {
__weak <<<Type of Self>>> *__self = self;
[self PhotoCount:^(NSUInteger photoCount) {
__self.numberOfPhotos = photoCount;
[__self.collectionView reloadData];
}];
}
- (NSInteger)collectionView:(UICollectionView *)view numberOfItemsInSection:(NSInteger)section {
return self.numberOfPhotos;
}
如果您可以在视图出现之前将照片计数信息设置到您的班级,那可能是理想的选择。否则,您必须在之后插入内容。这不是理想的,在这种情况下,这并不完全是我要做的。但是这个问题开始偏离数据源,委托模式和应用程序架构 - 远远超出了方法的同步和异步返回值的问题。
希望有所帮助。
最后一句话回答了我认为你问的最后一个问题。更改您的数据重新加载调用,以便它在完成块中发生:
//Photo collection info
- (void)beginLoadingPhotoInfo {
NSLog(@"loaded beginloadingphotoinfo");
__weak CoverViewController *__self = self;
[self PhotoCount:^(NSUInteger photoCount) {
__self.numberOfPhotos = photoCount;
[__self.CoverView reloadData];
}];
}