0

上一篇:我正在尝试获取相机胶卷中的照片数量,我开始使用积木但遇到了一些困难。

现在:这是我更新的代码,我正在使用异步行为,但在我的块有机会完成之前返回一个值。

#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

有任何想法吗?

4

1 回答 1

1

您正在混合和匹配同步和异步方法。有两种可能的方法。

  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");}
         ];
    }
    

或者

  1. 阻塞当前线程,直到操作完成。在交互式用户应用程序中,这通常不是一个好主意。如果您这样做,您应该重新考虑应用程序的这一部分的结构:

    - (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];
    }];
}
于 2013-07-26T00:12:12.353 回答