目前还没有足够的声望来评论帖子。
但从苹果文档的外观来看,这个项目在滚动时deinits
图像,然后在它们即将被加载时re-inits
它们(请参见UIScrollView.m
中的第350行)。我还注意到ImageScrollView.m
内部有一个注释(第346行),明确说明这个类是为了避免缓存而设计的。这对于演示来说是一种实用的方式,但对于像您想要的那样考虑ui加载速度的生产或现实世界应用程序来说,则不是一个实用的方式。
我还注意到您的应用程序必须滚动得更远才能启用分页...这可能是代码中的某些错误,或者它本身就会使主线程停滞,无法流畅地运行分页。如果您打算使用如此宽的分页阈值...我建议您将其减小,以获得更好的用户体验,因为现代智能手机的屏幕比iPhone 4S的屏幕宽得多。
为了解决这个问题,
我在SO上找到了这个
post(下面),它似乎有一个相当不错的obj-c方法来缓存和获取应用程序启动后从这样的缓存帖子中的图像数据。您应该能够将其轻松地整合到启动后的方法中,甚至可以使用它与网络一起下载图像。您只需要确保您的UIImage视图正确链接到您使用的url字符串,通过为每个图像视图设置一组自定义字符串变量,或者通过将UImageView子类化为自定义类,并将缓存方法添加到其中以使您的代码看起来更简单。以下是来自
iOSfleer的该帖子中的方法和NSCahe类。
NSCache类:
@interface Sample : NSObject
+ (Sample*)sharedInstance;
- (void)cacheImage:(UIImage*)image forKey:(NSString*)key;
- (UIImage*)getCachedImageForKey:(NSString*)key;
@end
#import "Sample.h"
static Sample *sharedInstance;
@interface Sample ()
@property (nonatomic, strong) NSCache *imageCache;
@end
@implementation Sample
+ (Sample*)sharedInstance {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[Sample alloc] init];
});
return sharedInstance;
}
- (instancetype)init {
self = [super init];
if (self) {
self.imageCache = [[NSCache alloc] init];
}
return self;
}
- (void)cacheImage:(UIImage*)image forKey:(NSString*)key {
[self.imageCache setObject:image forKey:key];
}
- (UIImage*)getCachedImageForKey:(NSString*)key {
return [self.imageCache objectForKey:key];
}
为了不改变您已经做的太多,似乎通过更改ImageScrollview.m中的displayImageWithInfo方法为以下方法(使用缓存方法),在初始加载后它似乎工作得更好。如果我是您,我还会进一步实现一个循环式方法,在控制器的viewDidLoad方法中立即缓存这些图像,以便在启动时更快地加载。但这取决于您。
- (void)displayImageWithInfo:(ImageItem*)imageInfo
{
CGSize imageSize = (CGSize){.width = imageInfo.width, .height = imageInfo.height};
[self.imageView removeFromSuperview];
self.imageView = nil;
self.zoomScale = 1.0;
self.imageView = [[UIImageView alloc] initWithFrame:(CGRect){.origin.x = 0.0f, .origin.y = 0.0f, .size = imageSize}];
UIImage *image = [[Sample sharedInstance] getCachedImageForKey:imageInfo.path];
if(image)
{
NSLog(@"This is cached");
((UIImageView*)self.imageView).image = image;
}
else{
NSURL *imageURL = [NSURL URLWithString:imageInfo.path];
UIImage *image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:imageURL]];
if(image)
{
NSLog(@"Caching ....");
[[Sample sharedInstance] cacheImage:image forKey:imageInfo.path];
((UIImageView*)self.imageView).image = image;
}
}
[self addSubview:self.imageView];
[self configureForImageSize:imageSize];
}
我建议在滚动时不要从其父视图中删除视图,而是绕过此问题。添加视图是非常繁重的任务。再加上图像加载,对于像智能手机这样的小型CPU来说可能会非常沉重(因为它们还没有GPU)。为了强调这一点,甚至苹果也提到了一旦显示UIImages就不会重新渲染它们,措辞很微妙here,但它显然没有提到优化删除、重新添加和渲染视图后它们被显示一次(例如在这种情况下)。我认为这里的预期用途是显示ImageView
,并在控制器显示后简单地更改其image
元素。
虽然图像对象支持所有平台本机图像格式,但建议您在应用程序中使用PNG或JPEG文件来处理大多数图像。图像对象针对读取和显示这两种格式进行了优化,并且这些格式比大多数其他图像格式具有更好的性能。
这就是为什么视图通常在它们的父视图上添加/初始化,然后再加载任何可见的加载方法,如
viewWillAppear
和
viewDidAppear
,或者如果是在初始加载后完成,则它们很少被取消初始化,它们的内容通常是唯一被更改的东西,即使这样做,也通常是异步完成(如果从网络下载),或者是从缓存中完成的,某些初始化程序还可以自动完成此操作(您可以将其添加到我推荐的内容中):
使用imageNamed:inBundle:compatibleWithTraitCollection:方法(或
imageNamed:方法)从应用程序的主包(或其他已知包)中创建图像。由于这些方法会自动缓存图像数据,因此特别推荐经常使用的图像。
就个人而言,我会尝试采用UICollectionViews
的方法。值得注意的是,它们有代理来自动处理内容缓存,当视图滚出窗口时(这正是此演示的情况)。您也可以在这些方法中添加自定义代码,以更好地控制这些视图上的滚动效果。它们可能一开始有点棘手,但我可以证明,您想要实现的目标可以使用比此演示使用的代码少得多的代码来复制。我还会把这个演示是在2012年构建的事实作为提示...它是一个非常古老的演示,而UICollectionViews则出现在此演示最后更新的时间。因此,我认为这正是苹果一直以来的目标,因为所有面向内容的UIView子类都从UIScrollView继承某种方式(UICollectionView、UITableView、UITextView等)。值得一看!UICollectionViews。