现有的UITableView照片网格不能正确旋转? [英] existing UITableView photo grid not rotating correctly?

查看:122
本文介绍了现有的UITableView照片网格不能正确旋转?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想制作一个基本的照片网格,这是一个网格的小缩略图图像,当点击去到一个大版本的图像。我使用一个UITableView来完成这个。我的问题是,当我尝试添加旋转支持,我无法得到的表格重新绘制一个额外的图像行的网格。

I am trying to make a basic photo grid, that is a "grid" of small "thumbnail" images, that when clicked go to a big version of the image. I am using a UITableView to accomplish this. My problem is that when I try adding rotation support I cant get the table to redraw the grid with an extra row of images.

这里有一些我的代码,PLEASE (

Here's some of my code, PLEASE feel free to ask any question as I'm at my wits end on this one >:(

- (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);

}

感谢您的任何帮助!

Shredder

推荐答案

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

I think a table view is the wrong tool for a gallery. You're always going to go through some silliness to put multiple images in a single table view cell, you presumably aren't going to be using the didSelectRowAtIndexPath logic, etc. I'd suggest a UIScrollView instead (see example below).

但是,如果您决定使用表视图,则 [self.tableView reloadData] 解。但您的 cellForRowAtIndexPath 有很多问题:

But, if you were determined to use a table view, then [self.tableView reloadData] is the right solution. But your cellForRowAtIndexPath has quite a few problems:


  1. 如果您正在创建单元格,请创建 UIButtons 。然而,考虑到你的风景v纵向,正确处理,你必须小心。不难,但要小心。

  1. You should only create UIButtons if you're creating your cell. You'll have to take care, though, given your landscape v portrait orientation, of handling that properly. Not hard, but be careful.

您应该使用加载的单元格解除图像的缓存。他们真的是两个不同的东西,即使它可能觉得他们非常相似。无论如何,你肯定不应该根据图像是否被缓存来更改 cellForRowAtIndexPath 中的单元格的基本填充;

You should decouple the caching of images with the loading of cells. They really are two different things, even though it might feel like they're awfully similar. Regardless, you definitely shouldn't be changing the basics populating of a cell in cellForRowAtIndexPath based upon whether the image was cached or not; it just changes where you get the image.

与手头的问题无关,但我不会硬编码屏幕坐标。我不会惊讶地看到新的iOS设备在未来几个月/不同的分辨率。就个人而言,我根据可以适合的缩略图数量计算可以在屏幕上显示多少图片。 self.view.frame.width (您可以使用 cell.contentView.frame.width )。

Unrelated to the problem at hand, but I would't hard code screen coordinates. I wouldn't be surprised to see new iOS devices with different resolutions over the coming months/years. Personally, I calculate how many images I can fit on the screen based upon how many thumbnails I can fit self.view.frame.width (you might use cell.contentView.frame.width).

也可能与这里的问题无关,我永远不会建议从<$ c $调用 viewDidLoad c> viewWillAppear 。如果你想有一些共同的初始化例程,他们都使用,那么也许你可以这样做(但即使这有点马虎),但由于 viewDidLoad 正在调用 [super viewDidLoad] ,你最终会调用方法两次,你不知道iOS是否酷的。

Also probably unrelated to the problem here, I would never recommend calling viewDidLoad from viewWillAppear. If you want to have some common initialization routine that they both use, then maybe you can do that (but even that is a little sloppy), but given that viewDidLoad is calling [super viewDidLoad], you'll end up calling that super method twice, and you don't know if iOS is cool with that. Probably not disasterous, but I can't imagine that it's a good idea.

最后,也与你的问题无关,但你不需要使用因为 willAnimateRotationToInterfaceOrientation viewWillLayoutSubviews 的通知中心 UIDeviceOrientationDidChangeNotification

Finally, also unrelated to your problem, but you don't need to use the notification center for UIDeviceOrientationDidChangeNotification because the standard willAnimateRotationToInterfaceOrientation or viewWillLayoutSubviews will do that for us.

如果你想做一个 UIScrollView 版本的图库,延迟加载来自远程服务器的图像,利用缓存的缩略图,检测到图像上的水龙头等,它可能看起来像下面。我提请你注意绝对没有任何肖像/风景逻辑(因为它只是看着scrollview的尺寸),但它处理方向变化很好。我没有包括,但是,我的代码填充 NSArray * imageUrlStrings ,因为这显然是完全独特的一个特定的应用程序,但你可能得到的想法。并且有各种各样的优化(例如使用 Reachability ),但这是一个可以为你完成工作的图库的shell。

If you wanted to do a UIScrollView version of a gallery with lazy loading of images from a remote server, leveraging a cache for the thumbnails, detecting a tap on the images, etc. it might look like the following. I draw your attention to an absolute absence of any portrait/landscape logic (because it just looks at the dimensions of the scrollview), but it handles orientation changes perfectly well. I have not included, though, my code for populating NSArray *imageUrlStrings because that's obviously completely unique to a particular app, but you probably get the idea nonetheless. And there are all sorts of optimizations you could do (e.g. use Reachability), but this is a shell of a gallery that might do the job for you.

//  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 单例对象。 (无论你是实现这个单身,是由你;你不必,但它的方便给予我的应用程序的性质。)我更新了封装次要文档 cache(因此你正在从一个远程服务器检索图像,缓存在 NSCache 对象以获得最佳性能,其次缓存在文档文件夹,如果要保存程序的后续调用从需要重新检索服务器的映像,给您跨会话的持久缓存)。这理论上可以(应该)被优化以清除长时间没有使用的图像的文档文件夹,但我将留给别人实现。

My ThumbnailCache is just a simple NSCache singleton object. (Whether you implement this as a singleton, is up to you; you don't have to but it's convenient given the nature of my apps.) I've updated this to encapsulate a secondary Documents cache (thus you're retrieving images from a remote server, cached in both the NSCache object for optimal performance, and secondarily cached in the Documents folder if you want to save subsequent invocations of the program from needing to re-retrieve the images from the server, giving you a persistent cache across sessions). This theoretically could (should?) be optimized to purge the Documents folder of images that haven't been used for a long time, but I'll leave that for others to implement.

//
//  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

I’d be surprised if there weren’t some great publicly available gallery classes, too, but if you wanted to roll your own, the above is a possibility.

I'd be surprised if there weren't some great publicly available gallery classes, too, but if you wanted to roll your own, the above is a possibility.

这篇关于现有的UITableView照片网格不能正确旋转?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆