2013-07-24 57 views
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 

有什麼想法嗎?

回答

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]; 
    }]; 
} 
+0

我將如何從另一種方法引用此方法?我在問題的底部添加了我的完整問題,因爲我不想在評論中使用很多代碼。 – lostAstronaut

+0

我已經更新瞭如何使用它的答案。這是一個非常輕的用法,並且可能您想要獲取並緩存關於照片的更多信息,只是有多少。每次需要關於它的特定信息時,您都不應該遍歷整個照片庫。 – Fabian

+0

嘿,我接受你的答案,因爲你是對的,並有不同的幫助。任何時候你都可以向我解釋什麼__Block <<<類型的自我>>> ext部分。 (我理解重裝數據,但之前的部分對我有點困惑 – lostAstronaut