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

同期と非同期の方法論を混ぜ合わせています。考えられるアプローチは 2 つあります。

  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 に答える