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

テーブルビューはギャラリーにとって間違ったツールだと思います。1つのテーブルビューセルに複数の画像を配置するために、常にいくつかの愚かさを経験することになります。おそらく、didSelectRowAtIndexPathロジックなどを使用することはないでしょう。代わりに、UIScrollView代わりに提案します(以下の例を参照)。

ただし、テーブルビューを使用することにした場合は、それ[self.tableView reloadData]が適切なソリューションです。しかし、あなたcellForRowAtIndexPathにはかなりの数の問題があります:

  1. UIButtonsセルを作成する場合にのみ作成する必要があります。ただし、横向きと縦向きの向きを考えると、それを適切に処理するように注意する必要があります。難しいことではありませんが、注意してください。

  2. 画像のキャッシュとセルの読み込みを切り離す必要があります。それらはひどく似ているように感じるかもしれませんが、実際には2つの異なるものです。cellForRowAtIndexPathとにかく、画像がキャッシュされているかどうかに基づいて、セルの基本的な入力を変更するべきではありません。画像を取得する場所が変わるだけです。

  3. 手元の問題とは関係ありませんが、画面の座標をハードコーディングしません。今後数か月/数年にわたって、解像度が異なる新しいiOSデバイスを見ても驚かないでしょう。個人的には、収まるサムネイルの数に基づいて、画面に収まる画像の数を計算しますself.view.frame.width(使用する場合がありますcell.contentView.frame.width)。

  4. また、おそらくここでの問題とは関係がないので、viewDidLoadから呼び出すことはお勧めしませんviewWillAppear。両方が使用する一般的な初期化ルーチンが必要な場合は、それを実行できますが(ただし、それでも少しずさんです)、viewDidLoad呼び出し[super viewDidLoad]ている場合は、そのsuperメソッドを2回呼び出すことになり、その方法はありません。 iOSがそれでかっこいいかどうかわからない。恐らく悲惨ではないでしょうが、それが良い考えだとは想像できません。

  5. 最後に、これもあなたの問題とは無関係ですがUIDeviceOrientationDidChangeNotification、標準willAnimateRotationToInterfaceOrientationまたは私たちのviewWillLayoutSubviewsためにそれを行うので、通知センターを使用する必要はありません。

リモートサーバーからの画像の遅延読み込み、サムネイルのキャッシュの活用、画像のタップの検出などを使用してギャラリーのUIScrollViewバージョンを作成する場合は、次のようになります。ポートレート/ランドスケープロジックがまったくないことに注意してください(スクロールビューの寸法を見るだけなので)が、向きの変更を完全に処理します。ただし、特定のアプリに完全に固有であるため、データを入力するためのコードは含めていませんが、NSArray *imageUrlStringsそれでもおそらくそのアイデアは得られます。そして、あなたが行うことができるあらゆる種類の最適化(例えば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シングルトンオブジェクトです。(これをシングルトンとして実装するかどうかはあなた次第です。必須ではありませんが、私のアプリの性質を考えると便利です。)セカンダリDocumentsキャッシュをカプセル化するようにこれを更新しました(したがって、リモートサーバー。NSCache最適なパフォーマンスのために両方のオブジェクトにキャッシュされDocuments、サーバーからイメージを再取得する必要がないようにプログラムの後続の呼び出しを保存する場合は、フォルダーに2番目にキャッシュされます。これにより、セッション間で永続的なキャッシュが提供されます。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 に答える