【iOS开发-45】Tom猫案例:动画、imageNamed与imageWithContentOfFile对内存影响、图片文件夹放哪儿以及文档注释

来源:互联网 发布:odn无源分配网络包括 编辑:程序博客网 时间:2024/05/22 00:34

今天tom猫案例效果:



(1)最傻最笨的办法:

——所有的点击都是按钮,只不过有6个有图标的按钮,有些头部、左右脚、肚子、尾巴那块也是一个按钮,只不过没背景没文字没边框的按钮用户按不到而已。

——这里的帧动画核心是UIImageView对象的一个属性animationImages,这个属性里面是以数组形式存放的图片。当然还有个重要的方法startAnimating用来播放前面那个属性里面的图片,就形成动画。再当然一下,还有设置时间和播放次数的属性。


注意点:

——我们一般把图片放在Images.xcassets里面,而且无论是png格式还是jpg格式貌似都可以省略后缀。

——目前为止,几乎只使用了一个代码简化方法,就是格式化输出,用%02d表示00、01......18、19......这些序列,从而导入众多的图片。

//使用3.5英寸屏幕模拟效果更好//无论是jpg还是png,在引用文件时都可以省略图片后缀#import "ViewController.h"@interface ViewController ()@property(nonatomic,retain) UIImageView *imgView1;@end@implementation ViewController- (void)viewDidLoad {    //中间的UIImageView,可以静态显示图片,下面动态播放帧动画也是用它    self.imgView1=[[UIImageView alloc]init];    self.imgView1.frame=CGRectMake(0, 0, 320, 512);    self.imgView1.image=[UIImage imageNamed:@"angry_00.jpg"];    self.imgView1.contentMode=UIViewContentModeScaleAspectFit;    [self.view addSubview:self.imgView1];        //定义6个看得见的按钮分列两边,另外还有头、左右脚、肚子、尾巴5个隐形按钮提供点击    UIButton *btnCymbal=[[UIButton alloc]init];    btnCymbal.frame=CGRectMake(5, 260, 60, 60);    [btnCymbal setImage:[UIImage imageNamed:@"cymbal.png"] forState:UIControlStateNormal];    [btnCymbal addTarget:self action:@selector(cymbalClick) forControlEvents:UIControlEventTouchUpInside];    [self.view addSubview:btnCymbal];        UIButton *btnDrink=[[UIButton alloc]init];    btnDrink.frame=CGRectMake(5, 340, 60, 60);    [btnDrink setImage:[UIImage imageNamed:@"drink.png"] forState:UIControlStateNormal];    [btnDrink addTarget:self action:@selector(drinkClick) forControlEvents:UIControlEventTouchUpInside];    [self.view addSubview:btnDrink];    UIButton *btnEat=[[UIButton alloc]init];    btnEat.frame=CGRectMake(5, 420, 60, 60);    [btnEat setImage:[UIImage imageNamed:@"eat.png"] forState:UIControlStateNormal];    [btnEat addTarget:self action:@selector(eatClick) forControlEvents:UIControlEventTouchUpInside];    [self.view addSubview:btnEat];    UIButton *btnFart=[[UIButton alloc]init];    btnFart.frame=CGRectMake(255, 260, 60, 60);    [btnFart setImage:[UIImage imageNamed:@"fart.png"] forState:UIControlStateNormal];    [btnFart addTarget:self action:@selector(fartClick) forControlEvents:UIControlEventTouchUpInside];    [self.view addSubview:btnFart];    UIButton *btnPie=[[UIButton alloc]init];    btnPie.frame=CGRectMake(255, 340, 60, 60);    [btnPie setImage:[UIImage imageNamed:@"pie.png"] forState:UIControlStateNormal];    [btnPie addTarget:self action:@selector(pieClick) forControlEvents:UIControlEventTouchUpInside];    [self.view addSubview:btnPie];    UIButton *btnScratch=[[UIButton alloc]init];    btnScratch.frame=CGRectMake(255, 420, 60, 60);    [btnScratch setImage:[UIImage imageNamed:@"scratch.png"] forState:UIControlStateNormal];    [btnScratch addTarget:self action:@selector(scratchClick) forControlEvents:UIControlEventTouchUpInside];    [self.view addSubview:btnScratch];        UIButton *btnLeftFoot=[[UIButton alloc]init];    btnLeftFoot.frame=CGRectMake(115, 455, 40, 25);    [btnLeftFoot addTarget:self action:@selector(leftFootClick) forControlEvents:UIControlEventTouchUpInside];    [self.view addSubview:btnLeftFoot];        UIButton *btnRightFoot=[[UIButton alloc]init];    btnRightFoot.frame=CGRectMake(160, 455, 40, 25);    [btnRightFoot addTarget:self action:@selector(rightFootClick) forControlEvents:UIControlEventTouchUpInside];    [self.view addSubview:btnRightFoot];        UIButton *btnHead=[[UIButton alloc]init];    btnHead.frame=CGRectMake(80, 90, 160, 160);    [btnHead addTarget:self action:@selector(headClick) forControlEvents:UIControlEventTouchUpInside];    [self.view addSubview:btnHead];        UIButton *btnStomach=[[UIButton alloc]init];    btnStomach.frame=CGRectMake(100, 330, 120, 120);    [btnStomach addTarget:self action:@selector(stomachClick) forControlEvents:UIControlEventTouchUpInside];    [self.view addSubview:btnStomach];        UIButton *btnTail=[[UIButton alloc]init];    btnTail.frame=CGRectMake(216, 380, 30, 80);    [btnTail addTarget:self action:@selector(tailClick) forControlEvents:UIControlEventTouchUpInside];    [self.view addSubview:btnTail];    [super viewDidLoad];    // Do any additional setup after loading the view, typically from a nib.}-(void)cymbalClick{    //先创建一个可变数组,并用for循环添加图片,因为图片太多,一个个添加会死人的。    NSMutableArray *muArr1=[[NSMutableArray alloc]init];    for (int i=0; i<13; i++) {        UIImage *tmpImg=[UIImage imageNamed:[NSString stringWithFormat:@"cymbal_%02d.jpg",i]];        [muArr1 addObject:tmpImg];    }    //把这个图片数组赋值给我们之前定义的UIImageView对象imgView1    self.imgView1.animationImages=muArr1;    //以下是设置帧动画的播放时间和播放次数,最后记得开始这个动画,其他类似相同    self.imgView1.animationRepeatCount=1;    self.imgView1.animationDuration=muArr1.count*0.1;    [self.imgView1 startAnimating];}-(void)drinkClick{    NSMutableArray *muArr1=[[NSMutableArray alloc]init];    for (int i=0; i<81; i++) {        UIImage *tmpImg=[UIImage imageNamed:[NSString stringWithFormat:@"drink_%02d.jpg",i]];        [muArr1 addObject:tmpImg];    }    self.imgView1.animationImages=muArr1;    self.imgView1.animationRepeatCount=1;    self.imgView1.animationDuration=muArr1.count*0.1;    [self.imgView1 startAnimating];}-(void)eatClick{    NSMutableArray *muArr1=[[NSMutableArray alloc]init];    for (int i=0; i<40; i++) {        UIImage *tmpImg=[UIImage imageNamed:[NSString stringWithFormat:@"eat_%02d.jpg",i]];        [muArr1 addObject:tmpImg];    }    self.imgView1.animationImages=muArr1;    self.imgView1.animationRepeatCount=1;    self.imgView1.animationDuration=1;    [self.imgView1 startAnimating];}-(void)fartClick{    NSMutableArray *muArr1=[[NSMutableArray alloc]init];    for (int i=0; i<28; i++) {        UIImage *tmpImg=[UIImage imageNamed:[NSString stringWithFormat:@"fart_%02d.jpg",i]];        [muArr1 addObject:tmpImg];    }    self.imgView1.animationImages=muArr1;    self.imgView1.animationRepeatCount=1;    self.imgView1.animationDuration=1;    [self.imgView1 startAnimating];}-(void)pieClick{    NSMutableArray *muArr1=[[NSMutableArray alloc]init];    for (int i=0; i<24; i++) {        UIImage *tmpImg=[UIImage imageNamed:[NSString stringWithFormat:@"pie_%02d.jpg",i]];        [muArr1 addObject:tmpImg];    }    self.imgView1.animationImages=muArr1;    self.imgView1.animationRepeatCount=1;    self.imgView1.animationDuration=1;    [self.imgView1 startAnimating];}-(void)scratchClick{    NSMutableArray *muArr1=[[NSMutableArray alloc]init];    for (int i=0; i<56; i++) {        UIImage *tmpImg=[UIImage imageNamed:[NSString stringWithFormat:@"scratch_%02d.jpg",i]];        [muArr1 addObject:tmpImg];    }    self.imgView1.animationImages=muArr1;    self.imgView1.animationRepeatCount=1;    self.imgView1.animationDuration=1;    [self.imgView1 startAnimating];}-(void)leftFootClick{    NSMutableArray *muArr1=[[NSMutableArray alloc]init];    for (int i=0; i<30; i++) {        UIImage *tmpImg=[UIImage imageNamed:[NSString stringWithFormat:@"footLeft_%02d.jpg",i]];        [muArr1 addObject:tmpImg];    }    self.imgView1.animationImages=muArr1;    self.imgView1.animationRepeatCount=1;    self.imgView1.animationDuration=1;    [self.imgView1 startAnimating];}-(void)rightFootClick{    NSMutableArray *muArr1=[[NSMutableArray alloc]init];    for (int i=0; i<30; i++) {        UIImage *tmpImg=[UIImage imageNamed:[NSString stringWithFormat:@"footRight_%02d.jpg",i]];        [muArr1 addObject:tmpImg];    }    self.imgView1.animationImages=muArr1;    self.imgView1.animationRepeatCount=1;    self.imgView1.animationDuration=1;    [self.imgView1 startAnimating];}-(void)headClick{    NSMutableArray *muArr1=[[NSMutableArray alloc]init];    for (int i=0; i<81; i++) {        UIImage *tmpImg=[UIImage imageNamed:[NSString stringWithFormat:@"knockout_%02d.jpg",i]];        [muArr1 addObject:tmpImg];    }    self.imgView1.animationImages=muArr1;    self.imgView1.animationRepeatCount=1;    self.imgView1.animationDuration=1;    [self.imgView1 startAnimating];}-(void)stomachClick{    NSMutableArray *muArr1=[[NSMutableArray alloc]init];    for (int i=0; i<34; i++) {        UIImage *tmpImg=[UIImage imageNamed:[NSString stringWithFormat:@"stomach_%02d.jpg",i]];        [muArr1 addObject:tmpImg];    }    self.imgView1.animationImages=muArr1;    self.imgView1.animationRepeatCount=1;    self.imgView1.animationDuration=1;    [self.imgView1 startAnimating];}-(void)tailClick{    NSMutableArray *muArr1=[[NSMutableArray alloc]init];    for (int i=0; i<26; i++) {        UIImage *tmpImg=[UIImage imageNamed:[NSString stringWithFormat:@"angry_%02d.jpg",i]];        [muArr1 addObject:tmpImg];    }    self.imgView1.animationImages=muArr1;    self.imgView1.animationRepeatCount=1;    self.imgView1.animationDuration=1;    [self.imgView1 startAnimating];}@end

(2)补全漏洞:动画一个动画的时候点击另一个按钮失效,即保证播放完当前动画才能操作下一个。

即,在每一个点击事件的方法代码中添加如下,判断这UIImageView的对象imaView1如果正在播放,那么直接返回,不做任何操作,否则,执行一次动画操作。

[self playTomWithName:@"stomach" Number:34];

(3)合并代码:相同的直接合并,不同的用参数传递来调整,即把11个点击方法重写成如下:

-(void)playTomWithName:(NSString *)name Number:(int)number{    if (self.imgView1.isAnimating) return;    NSMutableArray *muArr1=[[NSMutableArray alloc]init];    for (int i=0; i<number; i++) {        UIImage *tmpImg=[UIImage imageNamed:[NSString stringWithFormat:@"%@_%02d.jpg",name,i]];        [muArr1 addObject:tmpImg];    }    self.imgView1.animationImages=muArr1;    self.imgView1.animationRepeatCount=1;    self.imgView1.animationDuration=1;    [self.imgView1 startAnimating];}-(void)cymbalClick{    [self playTomWithName:@"cymbal" Number:13];}-(void)drinkClick{    [self playTomWithName:@"drink" Number:81];}-(void)eatClick{    [self playTomWithName:@"eat" Number:40];}-(void)fartClick{    [self playTomWithName:@"fart" Number:28];}-(void)pieClick{    [self playTomWithName:@"pie" Number:24];}-(void)scratchClick{    [self playTomWithName:@"scratch" Number:56];}-(void)leftFootClick{    [self playTomWithName:@"footLeft" Number:30];}-(void)rightFootClick{    [self playTomWithName:@"footRight" Number:30];}-(void)headClick{    [self playTomWithName:@"knockout" Number:81];}-(void)stomachClick{    [self playTomWithName:@"stomach" Number:34];}-(void)tailClick{    [self playTomWithName:@"angry" Number:26];}

(4)内存管理,imageNamed加载图像的弊端。

我们运行上述代码后,发现,多点击几次不同的按钮播放动画后,内存使用急剧上升。主要原因在于imageNamed加载图片的方法:它加载完图片后都存放在内存中,方便下次使用,所以内存中不断新增图片,会很大,在手机上会出现因为内存过载而闪退的现象。

点了几个按钮后,内存情况如下:


解决办法,用其他方法加载图片,用imageWithContentOfFile方法:这种方法不会将图片都加载到内存中,用完就释放了。

-(void)playTomWithName:(NSString *)name Number:(int)number{    if (self.imgView1.isAnimating) return;    NSMutableArray *muArr1=[[NSMutableArray alloc]init];    for (int i=0; i<number; i++) {        NSString *fileName=[NSString stringWithFormat:@"%@_%02d.jpg",name,i];        NSBundle *bundle1=[NSBundle mainBundle];        NSString *path=[bundle1 pathForResource:fileName ofType:nil];        UIImage *tmpImg=[UIImage imageWithContentsOfFile:path];        //        UIImage *tmpImg=[UIImage imageNamed:[NSString stringWithFormat:@"%@_%02d.jpg",name,i]];        [muArr1 addObject:tmpImg];    }    self.imgView1.animationImages=muArr1;    self.imgView1.animationRepeatCount=1;    self.imgView1.animationDuration=1;    [self.imgView1 startAnimating];}


但是,我们发现,内存使用仍然很高,这是因为我们点击按钮播放一组动画后,有self.imgView1.animationImages=muArr1;,这个muArr1没有被释放仍然存在,所以它animationImages里的所有图片也还在。

只是不会把所有的都加载,只是当前播放的那组图片会加载进来而已。


(5)再一次清除内存——再播放完动画后清除内存(其实也可以叫缓存)。

核心在于:要想清除缓存,只需要把self.imgView1.animationImages=nil;那么就没有强指针指向muArr1,muArr1就会被回收。

但,我们不能直接用上述语句,因为使用上述语句,会发现,动画还没有播放就已经被停止了,因为动画播放有一个时间持续,而执行上述的代码只需要极短时间。

所以?我们需要延迟执行上面的语句。延迟多少时间?比动画播放时间长1秒钟,差不多。


除了self.imgView1.animationImages=nil;之外,还可以利用方法进行nil赋值,语句是[self.imgView1 setAnimationImages:nil];

而延迟执行一个方法,正好有performSelector...afterDelay这个方法,所以:

    double delayNum=(double)self.imgView1.animationDuration+1.0;    [self.imgView1 performSelector:@selector(setAnimationImages:) withObject:nil afterDelay:delayNum];


(6)关于图片放在文件夹,文件夹直接拖放到Xcode中得问题。

直接的图片建议拖放到Images.xcassets中,但是如果是一个文件夹,不建议直接拖放到Images.xcassets,因为用mainBundle查找文件时查找不到。建议拖放到Supporting Files中。从两边文件夹颜色可分辨。总的来说:

——黄颜色的那个文件夹其实不能称之为文件夹,我们可以叫它组,它只是把图片分组而已,因为图片全部都被统一放在mainBudle中,而不是在这些“文件夹”中。

——蓝颜色的那个文件夹就是真正的文件夹,它是一种路径,如果要访问它里面的图片,那么我们需要写出这个文件夹。所以对我们用mainBundle查找文件十分不方便。



(7)补充:文档注释的写法

文档注释和普通注释不一样,文档注释更强大,不仅方便阅读,而且还提供动态输入时候的提示,即如下效果:


要实现这个效果,注释的格式如下,不管哪种方式,都是前面是/**后面是*/:

//写在一行/**HELLO,这里是文档注释*///写在多行/** HELLO,这里是文档注释 */

不要和普通注释的/* */混淆。

2 0
原创粉丝点击