以下是我要做的事情:我希望有一个显示全屏图像的应用程序,并通过滑动UISlider使该图像具有动画效果。更改滑块值将按顺序创建动画的阵列图像。此动画是转台上的单个字符。当滑块改变值时,角色看起来好像在转台上旋转。
该项目是3D艺术家的作品集。艺术家给了我一系列180幅图像,这些图像是在全屏视网膜分辨率下渲染的。他还提供了另外180张非视网膜全屏分辨率的图像。这个想法是,当有人在视网膜iPad上从任何角度观察他的角色时,他们可以使用视网膜和非视网膜显示器之间的UISwitch进行切换。下面发布的代码在模拟器上工作正常。
然而,当在iPad 4上运行此代码时,它可以工作一段时间,然后我收到内存警告。然后它崩溃了。我假设有那么多大小的图像显示速度和有人想要移动滑块一样快,iPad 4无法处理。
我很好奇在处理这样的图像时我应该考虑哪些限制。 180张图片太多了吗?什么是合理的金额?有没有更有效的方法来产生我想要的结果?我认为有人可能对我的问题有一些有用的见解,而不是使用猜测和检查方法来确定有多少图像不会导致崩溃。
@implementation RBViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
_imageDisplay.image = [UIImage imageNamed:@"HyperReal_0.png"];
_arrayRetina = [[NSMutableArray alloc] initWithCapacity:180];
_arrayNormal = [[NSMutableArray alloc] initWithCapacity:180];
for(int i = 0; i < 179; i++)
{
NSString *myImageString = [[NSString alloc] initWithFormat:@"HyperReal_%i.png", i];
UIImage *myImageGraphic = [UIImage imageNamed:myImageString];
[_arrayRetina addObject:myImageGraphic];
}
for(int i = 0; i < 179; i++)
{
NSString *myImageString = [[NSString alloc] initWithFormat:@"lameHyperReal_%i.png", i];
UIImage *myImageGraphic = [UIImage imageNamed:myImageString];
[_arrayNormal addObject:myImageGraphic];
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)switchButton:(id)sender {
if (_switchOnForRetina.isOn == YES)
{
_imageDisplay.image = [_arrayRetina objectAtIndex:_sliderBar.value];
}
else
_imageDisplay.image = [_arrayNormal objectAtIndex:_sliderBar.value];
}
- (IBAction)changeSlider:(id)sender {
if (_switchOnForRetina.isOn == YES)
{
_imageDisplay.image = [_arrayRetina objectAtIndex:_sliderBar.value];
}
else
_imageDisplay.image = [_arrayNormal objectAtIndex:_sliderBar.value];
}
@end
答案 0 :(得分:1)
不是一次将所有180个图像加载到数组中,而是无法在滑块的连续UIContolEventValueChanged事件中实例化当前图像?
创建滑块
UISlider *slider = [[UISlider alloc] initWithFrame:CGRectMake(0, 0, 155, 20)];
slider.continuous = YES;
slider.value = 0.0f;
slider.minimumValue = 0.0f;
slider.minimumValue = 179.0f;
[slider addTarget:self action:@selector(handleContinuousSlider:) forControlEvents:UIControlEventValueChanged];
处理它的持续变化事件
- (void)handleContinuousSlider:(UISlider *)slider {
//create a UIImage with file name that makes the current integer value of the slider
NSString *myImageString = [[NSString alloc] initWithFormat:@"HyperReal_%i.png", slider.value];
UIImage *myImageGraphic = [UIImage imageNamed:myImageString];
//I assume this is a UIImageView
[_imageDisplay setImage:myImageGraphic];
[myImageGraphic release];
}
答案 1 :(得分:1)
我不太确定为什么你需要以编程方式在Retina和非Retina之间切换,因为@ 2x处理得非常好,但是我会假设有一个我不熟悉的用例并且会留下它在那。
关于内存使用情况,我们正在开发具有类似功能的应用程序,我们的解决方案是使用引用所有单个帧的图像名称(或文件路径)的字符串填充数组。在您的情况下,您将存储引用myImageString
而不是myImageGraphic
。
然后当您拖动滑块时,您会使用以下内容:
- (IBAction)changeSlider:(id)sender
{
if (_switchOnForRetina.isOn == YES)
_imageDisplay.image = [UIImage imageNamed:[_arrayRetina objectAtIndex:_sliderBar.value]];
else
_imageDisplay.image = [UIImage imageNamed:[_arrayNormal objectAtIndex:_sliderBar.value]];
}
另外一点,我们使用imageWithContentsOfFile
,因为内存使用量较低this post,但imageNamed
的缓存在这种情况下可能会有所帮助。
编辑:
正如mccrager所指出的,上述方法仅在修饰时发生变化。这是我正在使用的一个例子,虽然我在UIView上使用UIGestureRecognizer
来向方法发送百分比而不是依赖滑块。
- (void)dragPosition:(float)myPercent
{
NSInteger index = (self.images.count - 1) * myPercent;
NSString *imageName = [self.images objectAtIndex:index];
NSString *imagePath = [[NSBundle mainBundle] pathForResource:imageName ofType:@"jpg"];
self.image = [UIImage imageWithContentsOfFile:imagePath];
}
希望这有帮助!
答案 2 :(得分:1)
预先缓冲内存成本:
((2048 * 1536 * 4 + 1024 * 768 * 4)* 180)/ 1024/1024/1024 = 2.63671875千兆字节
即使进行了一些地下优化,你的iPad也没有足够的内存来安全地运行该程序。
作为解决崩溃问题的工作,请不要预先加载所有图片,而只需加载所需的图片
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[ self changeSlider: nil ];
}
- (IBAction)changeSlider:(id)sender {
if (_switchOnForRetina.isOn == YES)
{
_imageDisplay.image = nil;
NSString* pResourcePath = [ [ NSBundle mainBundle ] pathForResource: [ NSString stringWithFormat: @"HyperReal_%i", ( int )_sliderBar.value ] ofType: @"png" ];
_imageDisplay.image = [ UIImage imageWithContentsOfFile: pResourcePath ];
}
else
{
_imageDisplay.image = nil;
NSString* pResourcePath = [ [ NSBundle mainBundle ] pathForResource: [ NSString stringWithFormat: @"lameHyperReal_%i", ( int )_sliderBar.value ] ofType: @"png" ];
_imageDisplay.image = [ UIImage imageWithContentsOfFile: pResourcePath ];
}
}
这里更好的解决方案是从图像序列中创建2个h264电影
前进动画顺序中的一个,后退动画顺序中的第二个
然后根据滑块动画播放正确的电影
当然,这还有很多工作要做。
干杯