關於在App啟動時播放一段動畫,可以用flash直接播放,也可以用多張連續的圖片來實現,在項目中,我選擇了後者。
通過連續的多張圖片做出動畫效果,系統自帶的UIImageView就能完成這個功能,一開始我也這麼做的,但是最後發現內存爆了,占了800M多(iPAD)。(注:一張100K的png圖片初始化為Image放到內存後會占用幾M到幾十M的空間不等)
最後我選擇了通過定時器不斷刷新UIImageView.image的方法。
在這裡又被系統忽悠了一把。 [UIImgae imageName: ]和[UIImage imageWithContentsOfFile: ],這兩個方法從理論上說,前者是系統分配一塊內存緩存圖片,並在app生命 周期內一直存在,而後者是暫時存於內存,事後就釋放的。我用了後者,發現內存一樣爆掉,似乎(肯定)系統並沒有釋放內存。這個問題困擾了我半天,到底如何才能讓系統及時釋放這些空間,換個角度想可能更好,手動申請 —— 手動釋放。
於是我換成了[UIImage alloc]initWIthContentsOfFile: ]方法,這樣就成功的解決掉了內存無法釋放的問題。我的動畫圖片又106張,測試中發現只占了40-50M的空間,可以接受。
解決了內存問題,如何能讓圖片快速刷新就成了當務之急。
我建了個緩存池,後台異步讀取圖片到NSMutiableArray中,主線程從array中獲取image並定時刷新到ImageView中。這個方法在多核設備中性能有所提高,動畫更加流暢。
下面是核心代碼:
[cpp]
- (void) precache
{
_cacheImages = TRUE;
_cacheImageArray = [[NSMutableArray alloc]initWithCapacity:0];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"################################ image swap begin #########################");
UIImage * img = nil;
for (int i =1; i < [_imageNames count]; i++)
{
if(_cacheImageArray.count <= KSwapImageNum) {
NSString * name = [_imageNames objectAtIndex:i];
img = [[UIImage alloc]initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:name ofType:nil]];
[_cacheImageArray addObject:img];
[img release];img = nil;
}else{
[_requestCondition lock];
[_requestCondition wait];
[_requestCondition unlock];
i--;
}
}
NSLog(@"################################ image swap end #########################");
});
}
- (void) setImageAtIndex:(NSInteger)index
{
_imageset = TRUE;
NSString * name = [_imageNames objectAtIndex:index];
// load the image from the bundle
UIImage * img = nil;
if (_cacheImages)
{
if (_cacheImageArray.count > 0) {
img = [_cacheImageArray objectAtIndex:0];
// set it into the view
_imageView.image = nil;
[_imageView setImage:img];
[_cacheImageArray removeObjectAtIndex:0];
if (_cacheImageArray.count <= KSwapImageMinNum) {
[_requestCondition signal];
}
img = nil;
}
}
else
{
img = [[UIImage alloc]initWithContentsOfFile:
[[NSBundle mainBundle] pathForResource:name ofType:nil]];
// set it into the view
[_imageView setImage:img];
[img release];img = nil;
}
}
- (void) precache
{
_cacheImages = TRUE;
_cacheImageArray = [[NSMutableArray alloc]initWithCapacity:0];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"################################ image swap begin #########################");
UIImage * img = nil;
for (int i =1; i < [_imageNames count]; i++)
{
if(_cacheImageArray.count <= KSwapImageNum) {
NSString * name = [_imageNames objectAtIndex:i];
img = [[UIImage alloc]initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:name ofType:nil]];
[_cacheImageArray addObject:img];
[img release];img = nil;
}else{
[_requestCondition lock];
[_requestCondition wait];
[_requestCondition unlock];
i--;
}
}
NSLog(@"################################ image swap end #########################");
});
}
- (void) setImageAtIndex:(NSInteger)index
{
_imageset = TRUE;
NSString * name = [_imageNames objectAtIndex:index];
// load the image from the bundle
UIImage * img = nil;
if (_cacheImages)
{
if (_cacheImageArray.count > 0) {
img = [_cacheImageArray objectAtIndex:0];
// set it into the view
_imageView.image = nil;
[_imageView setImage:img];
[_cacheImageArray removeObjectAtIndex:0];
if (_cacheImageArray.count <= KSwapImageMinNum) {
[_requestCondition signal];
}
img = nil;
}
}
else
{
img = [[UIImage alloc]initWithContentsOfFile:
[[NSBundle mainBundle] pathForResource:name ofType:nil]];
// set it into the view
[_imageView setImage:img];
[img release];img = nil;
}
}