0

私がやろうとしていることは次のとおりです。フルスクリーン画像を表示し、UISliderをスライドさせてその画像をアニメーション化するアプリが必要です。スライダーの値を変更すると、アニメーションを作成する配列の画像が順番に表示されます。このアニメーションは、ターンテーブル上の1人のキャラクターです。スライダーの値が変わると、キャラクターはターンテーブルの周りを回転しているように見えます。

このプロジェクトは、3Dアーティストのためのポートフォリオ作品です。アーティストは、フルスクリーンの網膜解像度でレンダリングされたキャラクターの180枚の画像のシーケンスを私にくれました。彼はまた、網膜以外のフルスクリーン解像度でレンダリングされた追加の180枚の画像を提供しました。アイデアは、誰かが網膜iPadで任意の角度からキャラクターを表示しているときに、UISwitchを使用して網膜ディスプレイと非網膜ディスプレイを切り替えることができるというものです。以下に投稿されたコードは、シミュレーターで正常に機能します。

ただし、このコードをiPad 4で実行すると、少しの間機能し、メモリの警告が表示されます。その後、クラッシュします。誰かがスライダーを動かしたいのと同じくらい速く表示されるそのサイズの多くの画像を持っていることは、iPad4が処理するには多すぎると思います。

このような画像を扱うときに考慮すべき制限について知りたいです。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
4

3 に答える 3

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];
}
于 2013-03-12T17:48:40.483 に答える
1

@2xはそれを非常にうまく処理するため、Retinaと非Retinaをプログラムで切り替える必要がある理由はよくわかりませんが、慣れていない使用例があると想定し、そのままにしておきます。

メモリ使用量に関しては、同様の機能を持つアプリに取り組んでおり、解決策は、すべての個々のフレームの画像名 (またはファイル パス) を参照する文字列を配列に設定することでした。あなたの場合、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ようにメモリ使用量が少ないために使用しますが、この場合はキャッシュが役立つ場合があります。imageNamed

編集:

mccrager が指摘したように、上記の方法は修正時にのみ変更されます。これは私が使用している例ですがUIGestureRecognizer、スライダーに依存するのではなく、メソッドにパーセントを送信するために UIView を使用しています。

- (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];
}

お役に立てれば!

于 2013-03-12T17:52:19.000 に答える
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 ムービーを作成することです。

1 つは順方向のアニメーション順序、2 番目は逆方向のアニメーション順序

次に、スライダーのアニメーションに応じて適切なムービーを再生します

もちろん、それはより多くの仕事です。

乾杯

于 2013-03-12T18:03:06.280 に答える