2012-07-28 76 views
0

我正在尝试制作一个基本的照片网格,即一个小的“缩略图”图像的“网格”,点击时会转到大图像。我正在使用UITableView来完成此操作。我的问题是,当我尝试添加旋转支持时,我不能让表格重新绘制一排额外的图像。现有的UITableView照片网格不能正确旋转?

下面是我的一些代码,请随时问任何问题,因为我在我无计可施这一> :(

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    static NSString *CellIdentifier = @"Cell"; 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 

     if(cell==nil){ 
     cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; 
    } 

    if(self.interfaceOrientation==UIInterfaceOrientationPortrait || self.interfaceOrientation==UIInterfaceOrientationPortraitUpsideDown){ 
     NSLog(@"portrait"); 
     for (int i=0; i < self.numberOfColumns; i++) { 
      if (self.photoIndex < [self.photosArray count] || self.shouldReload==TRUE) { 
       UIButton *imageButton = [[UIButton alloc]init]; 

       UIActivityIndicatorView *loadingActivityIndicator = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite]; 

       [imageButton addTarget:self action:@selector(imageClicked:) forControlEvents:UIControlEventTouchDown]; 
       switch (self.buttonNumber) { 
        case 1: 
         self.xCord=35.0f; 
         self.buttonNumber++; 
         break; 
        case 2: 
         self.xCord=213.25f; 
         self.buttonNumber++; 
         break; 
        case 3: 
         self.xCord=391.5f; 
         self.buttonNumber++; 
         break; 
        case 4: 
         self.xCord=569.75f; 
         self.buttonNumber=1; 
         break; 
       } 
       imageButton.frame = CGRectMake(self.xCord, 35.0f, 163.25f, 163.25f); 
       imageButton.tag = self.photoIndex; 
       imageButton.enabled=FALSE; 
       imageButton.imageView.contentMode = UIViewContentModeScaleAspectFit; 

       if(self.buttonsArray.count < self.photosArray.count)[self.buttonsArray addObject:imageButton]; 

       if([self.isInternetAvailableClass isInternetAvailable]==YES)[self downloadImages:self.photoIndex]; 
       cell.selectionStyle=UITableViewCellSelectionStyleNone; 
       [cell addSubview:imageButton]; 

       if(self.photoIndex < self.buttonsArray.count){ 
       if(![[self.buttonsArray objectAtIndex:self.photoIndex] currentImage]){ 

       loadingActivityIndicator.center = imageButton.center; 
       loadingActivityIndicator.hidesWhenStopped=TRUE; 

       } 
       } 
       if(self.activityIndicatorArray.count < self.photosArray.count){ 

        [self.activityIndicatorArray addObject:loadingActivityIndicator]; 
        if([self.isInternetAvailableClass isInternetAvailable]==YES){ 

         [loadingActivityIndicator startAnimating]; 

        } 

       }else{ 
        if(self.photoIndex < self.buttonsArray.count){ 
        [self.activityIndicatorArray replaceObjectAtIndex:self.photoIndex withObject:loadingActivityIndicator]; 

        } 
       } 


       [cell addSubview:loadingActivityIndicator]; 
       self.photoIndex++; 
      } 
     } 

    return cell; 
    }else{ 
     NSLog(@"landscape called!"); 
     for (int i=0; i < self.numberOfColumns; i++) { 
      if (self.photoIndex < [self.photosArray count] || self.shouldReload==TRUE){ 
       NSLog(@"inside landscape called!"); 
       UIButton *imageButton = [[UIButton alloc]init]; 

       UIActivityIndicatorView *loadingActivityIndicator = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite]; 

       [imageButton addTarget:self action:@selector(imageClicked:) forControlEvents:UIControlEventTouchDown]; 
       switch (self.buttonNumber) { 
        case 1: 
         self.xCord=37; 
         self.buttonNumber++; 
         break; 
        case 2: 
         self.xCord=230; 
         self.buttonNumber++; 
         break; 
        case 3: 
         self.xCord=423; 
         self.buttonNumber++; 
         break; 
        case 4: 
         self.xCord=616; 
         self.buttonNumber++; 
         break; 
        case 5: 
         self.xCord=809; 
         self.buttonNumber=1; 
         break; 
       } 
       imageButton.frame = CGRectMake(self.xCord, 35.0f, 163.25f, 163.25f); 
       imageButton.tag = self.photoIndex; 
       imageButton.enabled=FALSE; 
       imageButton.imageView.contentMode = UIViewContentModeScaleAspectFit; 

       if(self.buttonsArray.count < self.photosArray.count){ 

        [self.buttonsArray addObject:imageButton]; 
       } 

       if([self.isInternetAvailableClass isInternetAvailable]==YES){ 

       [self downloadImages:self.photoIndex]; 
       } 
       cell.selectionStyle=UITableViewCellSelectionStyleNone; 
       [cell addSubview:imageButton]; 

       if(self.photoIndex < self.buttonsArray.count){ 
       if(![[self.buttonsArray objectAtIndex:self.photoIndex] currentImage]){ 

        loadingActivityIndicator.center = imageButton.center; 
        loadingActivityIndicator.hidesWhenStopped=TRUE; 
       } 
      } 
       if(self.activityIndicatorArray.count < self.photosArray.count){ 

        [self.activityIndicatorArray addObject:loadingActivityIndicator]; 
        if([self.isInternetAvailableClass isInternetAvailable]==YES){ 

         [loadingActivityIndicator startAnimating]; 

        } 

       }else{ 
        if(self.photoIndex < self.activityIndicatorArray.count){ 
        [self.activityIndicatorArray replaceObjectAtIndex:self.photoIndex withObject:loadingActivityIndicator]; 
        } 
       } 


       [cell addSubview:loadingActivityIndicator]; 
       self.photoIndex++; 
      } 
     } 

     return cell; 

    } 
    if (self.shouldReload==TRUE)self.shouldReload=FALSE; 
} 


#pragma mark - Table view delegate 
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ 
    return 205.0f; 
} 

#pragma mark - View Lifecycle 
- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    self.photosTableView = [[UITableView alloc]init]; 
    self.photosTableView.delegate=self; 
    self.photosTableView.dataSource=self; 
    self.photosTableView.separatorStyle = UITableViewCellSeparatorStyleNone; 
    self.photosTableView.backgroundColor = [UIColor clearColor]; 
    [self.view addSubview:self.photosTableView]; 

    self.isInternetAvailableClass = [[IsInternetAvailable alloc]init]; 
    self.buttonNumber=1; 
    self.xCord=0.0f; 
    self.downloadedImageNumber=0; 
    self.buttonsArray = [[NSMutableArray alloc]init]; 
    self.dataDictionary = [[NSMutableDictionary alloc]init]; 
    self.downloadedImagesArray = [[NSMutableArray alloc]init]; 
    self.activityIndicatorArray = [[NSMutableArray alloc]init]; 
    self.photosArray = [[NSMutableArray alloc]init]; 
    self.largePhotosArray = [[NSMutableArray alloc]init]; 
    self.imageOrderDictionary = [[NSMutableDictionary alloc]init]; 
    self.refToDownloadedImage = [[UIImage alloc]init]; 
    self.unformattedPhotosArray = [[NSMutableArray alloc]init]; 
    self.appDelegate = (StereophotoAppDelegate *)[[UIApplication sharedApplication]delegate]; 
    self.shouldReload=FALSE; 

    if(self.interfaceOrientation==UIInterfaceOrientationPortrait || self.interfaceOrientation==UIInterfaceOrientationPortraitUpsideDown){ 
     self.numberOfColumns=4; 
    }else{ 
     self.numberOfColumns=5; 
    } 

    self.photoIndex=0; 
    self.errorImageArray = [[NSMutableArray alloc]init]; 

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewWillAppear:) name:UIApplicationDidBecomeActiveNotification object:nil]; 
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(deviceDidRotate) name:UIDeviceOrientationDidChangeNotification object:nil]; 

    [self loadImages]; 
    } 
-(void)viewWillAppear:(BOOL)animated{ 
    self.appDelegate.isSlideshowRunning=NO; 
    self.appDelegate.PhotosPopoverSlideshowText = @"Start Slideshow"; 

    if([self.isInternetAvailableClass isInternetAvailable]==YES){ 

     if(self.isCommingFromNoNetworkConnectivity==YES){ 
      [self viewDidLoad]; 
     } 
     if(self.photosTableView.isHidden==YES)[self.photosTableView setHidden:NO]; 
     self.isCommingFromNoNetworkConnectivity=NO; 
    }else{ 

     if(self.photosTableView.isHidden==NO){ 

      [self.photosTableView setHidden:YES]; 

      self.isCommingFromNoNetworkConnectivity=YES; 
     } 
     UIAlertView *errorAlert = [[UIAlertView alloc]initWithTitle:@"Oops!" message:@"No Internet connection was detected! Please connect to the Internet and try again!" delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil]; 
     [errorAlert show]; 
    } 
} 
-(void)viewWillDisappear:(BOOL)animated{ 
    for(NSURLConnection *connection in self.connectionsArray){ 
     [connection cancel]; 
    } 
} 
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{ 
    return TRUE; 
} 
-(void)deviceDidRotate{ 
    self.photosTableView.frame=CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height); 

    if(self.interfaceOrientation==UIInterfaceOrientationPortrait || self.interfaceOrientation==UIInterfaceOrientationPortraitUpsideDown){ 
     self.numberOfColumns=4; 
    }else{ 
     self.numberOfColumns=5; 
    } 
    self.shouldReload=TRUE; 
    [self.photosTableView reloadData]; 
} 
-(void)viewDidAppear:(BOOL)animated{ 
    self.photosTableView.frame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height); 

} 

任何帮助的感谢吧!

碎纸机

+0

我还没有经历代码,但我正确的假设它在横向模式下工作,如果你在横向模式下启动,它只是方向的变化是有问题的?如果是这样,只需在'willAnimateRotationToInterfaceOrientation'中调用'[self.tableview reloadData]'。 – Rob 2012-07-28 01:34:19

+0

就我个人而言,我使用UIScrollView作为我的画廊网格,然后在'viewWillLayoutSubviews'上,我只是相应地调整框架。但这是一个更重大的重写。 – Rob 2012-07-28 01:35:59

+0

是的,如果你在lanscape模式下开始,它只有在以肖像开始然后旋转时才能正常工作。问题是如果你调用'[self.tableview reloadData]; '在载入cellForRowAtIndexPath中的if语句后,doesent调用函数的其余部分,除非您将self.photoIndex设置回0,从而混淆了活动指示符。 – Shredder2794 2012-07-28 03:20:19

回答

2

我认为表格视图是一个画廊的错误工具,你总是会经历一些愚蠢的情况,把多个图像放在一个单独的表格视图单元格中,你可能不会使用逻辑逻辑等等didSelectRowAtIndexPath我会建议UIScrollView inste广告(请参阅下面的示例)。

但是,如果您决定使用表格视图,那么[self.tableView reloadData]是正确的解决方案。但是,你的cellForRowAtIndexPath有不少问题:

  1. 您应该只创建UIButtons如果你创建你的。尽管如此,您必须小心谨慎,因为您的风景和人物肖像方向正确。不难,但要小心。

  2. 您应该将加载单元格的图像缓存解耦。他们真的是两回事,即使它们觉得他们非常相似。无论如何,您绝对不应该根据图像是否缓存来更改cellForRowAtIndexPath中单元格的基本填充内容;它只是改变你获得图像的位置。

  3. 无关手头的问题,但我不会硬编码屏幕坐标。在接下来的几个月/几年里,我将不会惊讶地发现具有不同分辨率的新iOS设备。就我个人而言,根据我可以放入多少个缩略图self.view.frame.width(您可能使用cell.contentView.frame.width),计算出我可以在屏幕上放入多少图像。

  4. 也可能与这里的问题无关,我绝不会建议从viewWillAppear呼叫viewDidLoad。如果你想有一些他们都使用的常见初始化程序,那么也许你可以做到这一点(但即使这样做有点sl)),但是假设viewDidLoad调用的是[super viewDidLoad],那么你最终会调用super方法两次,并且你不知道iOS是否很酷。可能不会造成灾难,但我无法想象这是个好主意。

  5. 最后,也无关你的问题,但你并不需要使用通知中心UIDeviceOrientationDidChangeNotification因为标准willAnimateRotationToInterfaceOrientationviewWillLayoutSubviews会替我们。

如果你想做一个UIScrollView版本从远程服务器的图像延迟加载一个画廊,撬动了缩略图的缓存,检测的图像等敲击它可能看起来像以下。我将注意力放在绝对不存在任何纵向/横向逻辑(因为它只是查看滚动视图的尺寸),但它能很好地处理方向的变化。不过,我没有包含我的代码,因为它对于特定的应用程序来说显然是完全独一无二的,但是您可能还是会明白这一点。并且可以进行各种优化(例如,使用Reachability),但这是可能为您完成这项工作的图库的外壳。

// GalleryViewController.m 

#import "GalleryViewController.h" 
#import "ThumbnailCache.h" 

#define IMAGE_WIDTH 76.0 
#define IMAGE_HEIGHT 76.0 

@interface MyImage : NSObject 

@property (nonatomic, strong) NSString *urlString; 
@property (nonatomic, strong) UIImageView *imageView; 
@property (nonatomic, strong) UIActivityIndicatorView *activityIndicator; 
@property (nonatomic, strong) UIView *view; 
@property BOOL loading; 
@property BOOL loaded; 

@end 

@implementation MyImage 

// I find that I generally can get away with loading images in main queue using Documents 
// cache, too, but if your images are not optimized (e.g. are large), or if you're supporting 
// older, slower devices, you might not want to use the Documents cache in the main queue if 
// you want a smooth UI. If this is the case, change kUseDocumentsCacheInMainQueue to NO and 
// then use the Documents cache only in the background thread. 

#define kUseDocumentsCacheInMainQueue YES 

- (id)init 
{ 
    self = [super init]; 
    if (self) 
    { 
     _view = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, IMAGE_WIDTH, IMAGE_HEIGHT)]; 
     _imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, IMAGE_WIDTH, IMAGE_HEIGHT)]; 
     _imageView.contentMode = UIViewContentModeScaleAspectFill; 
     _imageView.clipsToBounds = YES; 
     [_view addSubview:_imageView]; 
     _loading = NO; 
     _loaded = NO; 
    } 
    return self; 
} 

- (void)loadImage:(dispatch_queue_t)queue 
{ 
    if (self.loading) 
     return; 

    self.loading = YES; 

    ThumbnailCache *cache = [ThumbnailCache sharedManager]; 

    if (self.imageView.image == nil) 
    { 
     UIImage *imageFromCache = [cache objectForKey:self.urlString useDocumentsCache:kUseDocumentsCacheInMainQueue]; 
     if (imageFromCache) 
     { 
      if (self.activityIndicator) 
      { 
       [self.activityIndicator stopAnimating]; 
       self.activityIndicator = nil; 
      } 

      self.imageView.image = imageFromCache; 
      self.loading = NO; 
      self.loaded = YES; 
      return; 
     } 

     if (self.activityIndicator == nil) 
     { 
      self.activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; 
      self.activityIndicator.center = CGPointMake(self.view.frame.size.width/2.0, self.view.frame.size.height/2.0); 
      [self.view addSubview:self.activityIndicator]; 
     } 
     [self.activityIndicator startAnimating]; 

     dispatch_async(queue, ^{ 
      if (self.loading) 
      { 
       UIImage *image = nil; 

       // only requery cache for Documents cache if we didn't do so in the main queue 

       if (!kUseDocumentsCacheInMainQueue) 
        image = [cache objectForKey:self.urlString useDocumentsCache:YES]; 

       // if we haven't gotten the image yet, retrieve it from the remote server 

       if (!image) 
       { 
        NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:self.urlString]]; 

        if (data) 
        { 
         image = [UIImage imageWithData:data]; 
         [cache setObject:image forKey:self.urlString data:data]; 
        } 
       } 

       // now update the UI in the main queue 

       dispatch_async(dispatch_get_main_queue(), ^{ 
        if (self.loading) 
        { 
         [self.activityIndicator stopAnimating]; 
         self.activityIndicator = nil; 
         self.imageView.image = image; 
         self.loading = NO; 
         self.loaded = YES; 
        } 
       }); 
      } 
     }); 
    } 
} 

- (void)unloadImage 
{ 
    NSLog(@"%s %@", __FUNCTION__, self.urlString); 

    // remove from imageview, but not cache 

    self.imageView.image = nil; 

    self.loaded = NO; 
    self.loading = NO; 
} 

@end 


@interface GalleryViewController() 
{ 
    NSMutableArray *_myImages; 
    dispatch_queue_t _queue; 
} 
@end 

@implementation GalleryViewController 

- (void)dealloc 
{ 
    if (_queue) 
     dispatch_release(_queue); 

    [[NSNotificationCenter defaultCenter] removeObserver:self 
                name:UIApplicationDidBecomeActiveNotification 
                object:nil]; 
} 

- (void)didReceiveMemoryWarning 
{ 
    [super didReceiveMemoryWarning]; 

    // this is not strictly necessary because `NSCache` will automatically 
    // evict objects in low memory situations; it will not, though 
    // remove items when you try to simulate a low memory situation 
    // in the simulator, but it really will empty the cache when 
    // memory really runs low 
    // 
    // ThumbnailCache *cache = [ThumbnailCache sharedManager]; 
    // [cache removeAllObjects]; 
} 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    self.scrollView.delegate = self; 

    _queue = dispatch_queue_create("com.robertmryan.imageloader", NULL); 

    [self loadImages]; 

    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapHandler:)]; 
    [self.scrollView addGestureRecognizer:tap]; 

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appDidBecomeActive) name:UIApplicationDidBecomeActiveNotification object:nil]; 
} 

- (void)viewWillLayoutSubviews 
{ 
    NSUInteger imagesPerRow = (self.view.frame.size.width/IMAGE_WIDTH); 
    CGFloat imageMargin = (self.view.frame.size.width - (IMAGE_WIDTH * imagesPerRow))/(imagesPerRow + 1.0); 

    NSUInteger row = 0; 
    NSUInteger col = -1; 

    for (NSUInteger i = 0; i < [_myImages count]; i++) 
    { 
     col++; 
     if (col >= imagesPerRow) 
     { 
      col = 0; 
      row++; 
     } 

     MyImage *myImage = [_myImages objectAtIndex:i]; 
     CGRect frame = myImage.view.frame; 
     frame.origin.x = imageMargin + (imageMargin + IMAGE_WIDTH) * col; 
     frame.origin.y = imageMargin + (imageMargin + IMAGE_HEIGHT) * row; 
     myImage.view.frame = frame; 
    } 

    self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width, (row + 1) * (IMAGE_HEIGHT + imageMargin) + imageMargin); 

    [self displayVisibleImages:NO]; 
} 

- (void)viewDidUnload 
{ 
    [self setScrollView:nil]; 
    _myImages = nil; 

    [super viewDidUnload]; 
} 

- (void)viewWillAppear:(BOOL)animated 
{ 
    [super viewWillAppear:animated]; 

    [self displayVisibleImages:NO]; 
} 

- (void)appDidBecomeActive 
{ 
    [self displayVisibleImages:YES]; 
} 

- (void)displayVisibleImages:(BOOL)forceLoad 
{ 
    CGPoint contentOffset = self.scrollView.contentOffset; 
    CGRect contentFrame = self.scrollView.bounds; 
    contentFrame.origin = contentOffset; 

    for (MyImage *myImage in _myImages) 
    { 
     if (CGRectIntersectsRect(contentFrame, myImage.view.frame)) 
     { 
      // if the image is visible, then make sure it's loaded 

      if (!myImage.loaded || forceLoad) 
       [myImage loadImage:_queue]; 
     } 
     else 
     { 
      // if not, go ahead and unload it to conserve memory 

      if (myImage.loaded || myImage.loading) 
       [myImage unloadImage]; 
     } 
    } 
} 

- (void)scrollViewDidScroll:(UIScrollView *)scrollView 
{ 
    [self displayVisibleImages:NO]; 
} 

- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration 
{ 
    CGFloat version = [[[UIDevice currentDevice] systemVersion] floatValue]; 

    if (version < 5.0) 
     [self viewWillLayoutSubviews]; 
} 

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 
{ 
    return TRUE; 
} 

- (void)tapHandler:(UITapGestureRecognizer *)sender 
{ 
    CGPoint location = [sender locationInView:self.scrollView]; 

    for (MyImage *myImage in _myImages) 
    { 
     if (CGRectContainsPoint(myImage.view.frame, location)) 
      NSLog(@"Tapped in image %1d", myImage.view.tag); 
    } 
} 

- (void)loadImages 
{ 

    NSArray *imageUrlStrings = [self loadImageUrls]; 
    _myImages = [[NSMutableArray alloc] init]; 

    NSUInteger imagesPerRow = (self.scrollView.frame.size.width/IMAGE_WIDTH); 
    CGFloat imageMargin = (self.scrollView.frame.size.width - (IMAGE_WIDTH * imagesPerRow))/(imagesPerRow + 1.0); 

    NSInteger row = 0; 
    NSInteger col = -1; 

    for (NSUInteger i = 0; i < [imageUrlStrings count]; i++) 
    { 
     col++; 
     if (col >= imagesPerRow) 
     { 
      col = 0; 
      row++; 
     } 

     MyImage *myImage = [[MyImage alloc] init]; 
     myImage.urlString = [imageUrlStrings objectAtIndex:i]; 
     CGRect frame = myImage.view.frame; 
     frame.origin.x = imageMargin + (imageMargin + IMAGE_WIDTH) * col; 
     frame.origin.y = imageMargin + (imageMargin + IMAGE_HEIGHT) * row; 
     myImage.view.frame = frame; 
     [self.scrollView addSubview:myImage.view]; 
     myImage.view.tag = i; 

     [_myImages addObject:myImage]; 
    } 

    self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width, (row + 1) * (IMAGE_HEIGHT + imageMargin) + imageMargin); 
} 

@end 

ThumbnailCache只是一个简单的NSCache单独的对象。 (无论你是以singleton的形式实现它,取决于你;你不需要,但考虑到我的应用程序的特性,这很方便。)我已经更新了这个以封装第二个Documents缓存(因此你从一个远程服务器,缓存在NSCache对象中以获得最佳性能,如果要保存程序的后续调用,从而需要从服务器重新检索映像,则在缓存在Documents文件夹中,从而为您提供跨会话的持久性缓存)。这理论上可以(应该?)优化以清除长时间未使用的图像的文件夹,但我会留给其他人实施。

// 
// ThumbnailCache.h 
// 
// Created by Robert Ryan on 7/17/12. 
// Modified 8/9/12 to support secondary Documents-based cache. 
// 

#import <UIKit/UIKit.h> 

@interface ThumbnailCache : NSCache 

+ (id)sharedManager; 

- (id)objectForKey:(id)key useDocumentsCache:(BOOL)useDocumentsCache; 
- (void)setObject:(UIImage *)image forKey:(id)key data:(NSData *)data; 

@end 

// 
// ThumbnailCache.m 
// 
// Created by Robert Ryan on 7/17/12. 
// Modified 8/9/12 to support secondary Documents-based cache. 
// 

#import "ThumbnailCache.h" 

@implementation ThumbnailCache 

- (id)init 
{ 
    self = [super init]; 
    if (self) 
    { 
     self.name = @"Thumbnail cache"; 
    } 

    return self; 
} 

+ (id)sharedManager 
{ 
    static ThumbnailCache *sharedMyManager = nil; 
    static dispatch_once_t onceToken; 
    dispatch_once(&onceToken, ^{ 
     sharedMyManager = [[self alloc] init]; 
    }); 
    return sharedMyManager; 
} 

- (id)objectForKey:(id)key 
{ 
    return [self objectForKey:key useDocumentsCache:YES]; 
} 

- (id)objectForKey:(id)key useDocumentsCache:(BOOL)useDocumentsCache 
{ 
    // This is a variation of the standard objectForKey method which takes an additional 
    // parameter, useDocumentsCache, which will tell this to also check the Documents 
    // cache or not. This is a subtle refinement in case you don't want your main queue 
    // to use the Documents cache. Generally, if you're dealing with optimized images, 
    // this is not necessary, but if you're dealing with large images, this permutation 
    // can be useful. 

    // first, just try to get the image from the NSCache 

    id result = [super objectForKey:key]; 

    // if successful (or if we don't want to look in the Documents cache), then just return. 

    if (result || !useDocumentsCache) 
     return result; 

    // otherwise, if we didn't find it in the NSCache and we want to look in our Documents 
    // cache, then let's do so 

    NSString *path = [self pathInDocumentCache:key]; 

    if (!result && path) 
    { 
     // get the data from the remote server 

     NSData *data = [NSData dataWithContentsOfFile:path]; 
     if (data) 
     { 
      // and if we found it, save it in our NSCache 

      UIImage *image = [UIImage imageWithData:data]; 
      if (image) 
       [self setObject:image forKey:key]; 

      return image; 
     } 
    } 

    return result; 
} 

- (void)setObject:(UIImage *)image forKey:(id)key data:(NSData *)data 
{ 
    // This is a variation of the standard setObject:forKey which takes an additional NSData. 
    // The notion is that our cache stores UIImage objects (to save the theoretical overhead, 
    // if any, of loading image data into a NSData and then into a UIImage ... I wouldn't be 
    // surprised if Apple did some cool optimization of UIImage objects, though I don't know), 
    // so if we want to write our image file, but don't want to convert the UIImage back to 
    // a NSData, then let's just take the original NSData as a parameter. 

    // save the object in the NSCache 

    [super setObject:image forKey:key]; 

    // now let's also save the NSData in our Documents-based cache 

    NSFileManager *fileManager = [NSFileManager defaultManager]; 
    NSString *path = [self pathInDocumentCache:key]; 

    if (path && ![fileManager fileExistsAtPath:path]) 
    { 
     // let's create the folder if we need to 

     NSString *folder = [path stringByDeletingLastPathComponent]; 
     if (![fileManager fileExistsAtPath:folder]) 
      [fileManager createDirectoryAtPath:folder withIntermediateDirectories:YES attributes:nil error:nil]; 

     // and let's write the NSData to that folder 

     [data writeToFile:path atomically:YES]; 
    } 
} 

- (NSString *)pathInDocumentCache:(NSString *)key 
{ 
    if (![key isKindOfClass:[NSString class]]) 
     return nil; 

    NSString *docsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; 
    NSString *imagePath = [docsPath stringByAppendingPathComponent:@"image_cache"]; 
    NSURL *url = [NSURL URLWithString:key]; 

    return [imagePath stringByAppendingPathComponent:[url relativePath]]; 
} 

@end 

我会感到惊讶,如果有没有一些伟大的公开可用的库类,太多,但如果你想推出自己的,上面是一个可能性。

+0

非常感谢!由于我对iOS开发不熟悉,因此我不知道这一点。再次谢谢你! – Shredder2794 2012-07-28 15:05:26

+0

我有很多东西在我的盘子上,学校开始和东西,我只是现在开始玩这个代码。除非旋转设备时,网格不会重新绘制以包含更多(或更少)“列”。我的意思是如果我在网格中有7张图像,第一行是5,第二行是2,当我旋转设备时,网格保持不变,也就是说,顶部行仍然有5张图像, 2在第二个。下一个评论 – Shredder2794 2012-08-04 00:42:01

+0

没有试图成为一个帮助吸血鬼,但我怎么去设置它,当你旋转设备它重绘图像的数量,以配合可用的景观? – Shredder2794 2012-08-04 00:42:25