现有的 UITableView 照片网格没有正确旋转?

Posted

技术标签:

【中文标题】现有的 UITableView 照片网格没有正确旋转?【英文标题】:existing UITableView photo grid not rotating correctly? 【发布时间】:2012-07-28 00:36:50 【问题描述】:

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


感谢您的帮助!

碎纸机

【问题讨论】:

我还没有完成代码,但是如果你以横向模式开始,我假设它在横向模式下工作是正确的,而且只是方向的改变有问题吗?如果是这样,只需在willAnimateRotationToInterfaceOrientation 中调用[self.tableview reloadData] 就我个人而言,我使用 UIScrollView 作为我的画廊网格,然后在 viewWillLayoutSubviews 上我只是相应地调整框架。但这是一个更实质性的重写。 是的,如果您以横向模式开始,它只有在您以纵向开始然后旋转它时才能正常工作。问题是,如果您在加载 [self.tableview reloadData]; 之后调用它,则 cellForRowAtIndexPath 中的 if 语句会插入并不会调用函数的其余部分,除非您将 self.photoIndex 设置回 0,这会弄乱活动指示器。 好的,我看到你尝试了reloadData,但没有注意到你有所有的条件逻辑。是的,您只需要使用不同的解决方案来了解图像是否已下载。依赖 self.photoIndex 不是正确的解决方案。无论表格视图单元是创建还是成功出列,创建新的 UIButtons 也是有问题的。正如从viewWillAppear 调用viewDidLoad 一样(即使您是根据网络状态的变化有条件地这样做)。最重要的是,我在这里看到了很多东西。 我们应该把它移到聊天中(而不是在 cmets 中做详细的事情)吗? chat.***.com/rooms/14554/… 【参考方案1】:

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

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

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

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

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

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

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

如果您想做一个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 文件夹中,给出您是跨会话的持久缓存)。这在理论上可以(应该?)进行优化,以清除长时间未使用的图像的 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

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

【讨论】:

非常感谢!因为我是 iOS 开发的新手,所以我不知道这个。再次感谢您! 我的盘子里有很多东西,比如开学等等,我现在才开始玩这个代码。它工作得很好,除了当您旋转设备时,网格不会重新绘制以包含更多(或更少)“列”。我的意思是,如果我在网格中有 7 个图像,第一行有 5 个图像,第二行有 2 个图像,当我旋转设备时,网格保持不变,也就是说,顶行仍然有 5 个图像,并且2 在第二个。阅读下一条评论 不想成为帮助吸血鬼,但我将如何设置它,当您旋转设备时,它会重新绘制图像数量以匹配可用的景观? 这个视图是标签栏中的四个根视图控制器之一。我还没有做任何诊断工作。我会让你知道当我这样做时会发生什么。真的,我非常感谢你帮助我解决这个问题。 我明白了。问题是我已经通过情节提要将 ScrollView 放入视图控制器中,并且在加载视图时以某种方式干扰了我在代码中设置其框架。现在我正在通过代码创建滚动视图,效果很好!我无法解释我是多么感激你帮助我,因为在这篇文章之前我正要放弃!

以上是关于现有的 UITableView 照片网格没有正确旋转?的主要内容,如果未能解决你的问题,请参考以下文章

希望在现有的 UITabBarController 中创建 UINavigationView 或 UITableView

我的 UITableView 单元格没有给我正确的信息

具有 3 个自定义视图和动态高度的 UITableView

EXTJS 4 - 网格过滤器或商店过滤器清除商店现有的过滤器

iOS Objective C - 旋转回纵向后 UIView 无法正确显示

部分的 UITableView 标题仅在向下滚动时出现