0

我正在尝试制作一个基本的照片网格,即小“缩略图”图像的“网格”,单击时会转到图像的大版本。我正在使用 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);

}

谢谢你的帮助!

碎纸机

4

1 回答 1

2

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

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

  1. 只有UIButtons在创建单元格时才应该创建。但是,鉴于您的横向和纵向方向,您必须注意正确处理。不难,但要小心。

  2. 您应该将图像的缓存与单元格的加载分离。它们确实是两种不同的东西,即使感觉它们非常相似。无论如何,您绝对不应该cellForRowAtIndexPath根据图像是否缓存来更改单元格的基本填充;它只是改变你获得图像的位置。

  3. 与手头的问题无关,但我不会硬编码屏幕坐标。在接下来的几个月/几年中,如果看到具有不同分辨率的新 iOS 设备,我不会感到惊讶。就个人而言,我根据我可以容纳多少缩略图来计算我可以在屏幕上容纳多少图像self.view.frame.width(您可以使用cell.contentView.frame.width)。

  4. 也可能与这里的问题无关,我绝不建议viewDidLoadviewWillAppear. 如果你想有一些他们都使用的通用初始化例程,那么也许你可以这样做(但即使这有点草率),但鉴于viewDidLoad调用[super viewDidLoad],你最终会调用该super方法两次,而你没有'不知道iOS是否很酷。可能不是灾难性的,但我无法想象这是一个好主意。

  5. 最后,也与您的问题无关,但您不需要使用通知中心,UIDeviceOrientationDidChangeNotification因为标准willAnimateRotationToInterfaceOrientationviewWillLayoutSubviews将为我们这样做。

如果你想做一个UIScrollView从远程服务器延迟加载图像的画廊版本,利用缩略图缓存,检测对图像的点击等,它可能如下所示。我提请您注意绝对没有任何纵向/横向逻辑(因为它只查看滚动视图的尺寸),但它可以很好地处理方向变化。不过,我没有包含我的填充代码,NSArray *imageUrlStrings因为这显然是特定应用程序所独有的,但您可能还是明白了这个想法。您可以进行各种优化(例如 use 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

MyThumbnailCache只是一个简单的NSCache单例对象。(是否将其实现为单例,取决于您;您不必这样做,但考虑到我的应用程序的性质,它很方便。)我已经更新了它以封装二级Documents缓存(因此您从远程服务器,缓存在NSCache对象中以获得最佳性能,Documents如果您想保存程序的后续调用不需要从服务器重新检索图像,则缓存在文件夹中,从而为您提供跨会话的持久缓存)。从理论上讲,这可以(应该?)进行优化,以清除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

如果也没有一些很棒的公开可用的画廊课程,我会感到惊讶,但是如果你想自己动手,上面是一种可能性。

于 2012-07-28T07:43:10.067 回答