使用cadisplaylink三星手机内存增长器过快是什么情况

通过YYFPSLabel了解NSTimer,CADisplayLink内存泄漏问题及解决方案 - 简书
通过YYFPSLabel了解NSTimer,CADisplayLink内存泄漏问题及解决方案
YYFPSLabel是的YYKit库中一个查看屏幕帧数工具,下面我们来看看这个库吧,我用Swift重写了,这个工这篇文章我们通过Swift的代码来分析
什么是CADisplayLink
CADisplayLink是CoreAnimation提供的另一个类似于NSTimer的类,它总是在屏幕完成一次更新之前启动,它的接口设计的和NSTimer很类似,所以它实际上就是一个内置实现的替代,但是和timeInterval以秒为单位不同,CADisplayLink有一个整型的frameInterval属性,指定了间隔多少帧之后才执行。默认值是1,意味着每次屏幕更新之前都会执行一次。但是如果动画的代码执行起来超过了六十分之一秒,你可以指定frameInterval为2,就是说动画每隔一帧执行一次(一秒钟30帧)或者3,也就是一秒钟20次,等等。
YYFPSLabel实现原理
CADisplayLink可以以屏幕刷新的频率调用指定selector,而且iOS系统中正常的屏幕刷新率为60Hz(60次每秒),所以使用 CADisplayLink 的 timestamp 属性,配合 timer 的执行次数计算得出FPS数。
刷新频率 = 次数/时间
整个库主要包含两部分FPSLabel和WeakProxy,先看看FPSLabel吧,整体代码比较简单我就直接上代码,相关解释注释写的比较清楚
import UIKit
class FPSLabel: UILabel {
var _link:CADisplayLink!
//记录方法执行次数
var _count: Int = 0
//记录上次方法执行的时间,通过link.timestamp - _lastTime计算时间间隔
var _lastTime: TimeInterval = 0
var _font: UIFont!
var _subFont: UIFont!
fileprivate let defaultSize = CGSize(width: 55,height: 20)
override init(frame: CGRect) {
super.init(frame: frame)
if frame.size.width == 0 && frame.size.height == 0 {
self.frame.size = defaultSize
self.layer.cornerRadius = 5
self.clipsToBounds = true
self.textAlignment = NSTextAlignment.center
self.isUserInteractionEnabled = false
self.backgroundColor = UIColor.white.withAlphaComponent(0.7)
_font = UIFont(name: "Menlo", size: 14)
if _font != nil {
_subFont = UIFont(name: "Menlo", size: 4)
_font = UIFont(name: "Courier", size: 14)
_subFont = UIFont(name: "Courier", size: 4)
_link = CADisplayLink(target: WeakProxy.init(target: self), selector: #selector(FPSLabel.tick(link:)))
_link.add(to: RunLoop.main, forMode: .commonModes)
//CADisplayLink 刷新执行的方法
@objc func tick(link: CADisplayLink) {
guard _lastTime != 0 else {
_lastTime = _link.timestamp
_count += 1
let timePassed = link.timestamp - _lastTime
//时间大于等于1秒计算一次,也就是FPSLabel刷新的间隔,不希望太频繁刷新
guard timePassed &= 1 else {
_lastTime = link.timestamp
let fps = Double(_count) / timePassed
_count = 0
let progress = fps / 60.0
let color = UIColor(hue: CGFloat(0.27 * (progress - 0.2)), saturation: 1, brightness: 0.9, alpha: 1)
let text = NSMutableAttributedString(string: "\(Int(round(fps))) FPS")
text.addAttribute(NSAttributedStringKey.foregroundColor, value: color, range: NSRange(location: 0, length: text.length - 3))
text.addAttribute(NSAttributedStringKey.foregroundColor, value: UIColor.white, range: NSRange(location: text.length - 3, length: 3))
text.addAttribute(NSAttributedStringKey.font, value: _font, range: NSRange(location: 0, length: text.length))
text.addAttribute(NSAttributedStringKey.font, value: _subFont, range: NSRange(location: text.length - 4, length: 1))
self.attributedText = text
// 把displaylin从Runloop modes中移除
_link.invalidate()
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
NSTimer、CADisplayLink内存泄漏
如果_link = CADisplayLink(target: self, selector: #selector(FPSLabel.tick(link:))) Target 直接设置成 self 会造成内存泄漏。CADisplayLink强引用Target。当 CADisplayLink 加入 NSRunLoop 中,NSRunLoop会强引用CADisplayLink。如果仅仅在deinit中调用CADisplayLink的invalidate方法是没用的,因为NSRunLoop 一直都在,CADisplayLink不释放,Target被强引用,Target 的 deinit 方法不会被调用,CADisplayLink的invalidate方法也不被调用,CADisplayLink不会从NSRunLoop中移除
Screen Shot
at 11.05.02 PM.png
1.改变CADisplayLink的invalidate的方法调用时机
如果Target是UIViewController,在viewWillDisappear方法中调用CADisplayLink的invalidate的方法,但是如果Target是A那么A push或者present到B时CADisplayLink就被释放了,但实际上这个时候我们并不希望CADisplayLink被释放
2.通过Proxy避免避免CADisplayLink对Target的强引用
下面是WeakProxy的代码
import UIKit
class WeakProxy: NSObject {
weak var target: NSObjectProtocol?
init(target: NSObjectProtocol) {
self.target = target
super.init()
//Returns a Boolean value that indicates whether the receiver implements or inherits a method that can respond to a specified message.
override func responds(to aSelector: Selector!) -& Bool {
return (target?.responds(to: aSelector) ?? false) || super.responds(to: aSelector)
//系统会将aSelector转发给target执行
override func forwardingTarget(for aSelector: Selector!) -& Any? {
return target
Screen Shot
at 11.36.52 PM.png
_link = CADisplayLink(target: WeakProxy.init(target: self), selector: #selector(FPSLabel.tick(link:)))
_link.add(to: RunLoop.main, forMode: .commonModes)
weak var target: NSObjectProtocol?
WeakProxy对self进行了弱引用,这样self的 deinit就能被调用,然后 CADisplayLink的invalidate也会被调用,CADisplayLink成功被释放。
import UIKit
class CADisplayLinkProxy {
var displaylink: CADisplayLink?
var handle: (() -& Void)?
init(handle: (() -& Void)?) {
self.handle = handle
displaylink = CADisplayLink(target: self, selector: #selector(updateHandle))
displaylink?.add(to: RunLoop.current, forMode: .commonModes)
@objc func updateHandle() {
func invalidate() {
displaylink?.remove(from: RunLoop.current, forMode: .commonModes)
displaylink?.invalidate()
displaylink = nil
var displaylinkProxy = CADisplayLinkProxy(handle: { [weak self] in
self?.updateTime()
iOS10新的API已经支持NSTimer用Block解决这个问题了
if #available(iOS 10.0, *) {
self.timer = Timer(timeInterval: 6.0, repeats: true, block: { [weak self]
(timer) in
注意:使用weakSelf不能解决循环引用问题
那为什么这样可以解决循环引用呢?
weak var weakSelf = self
request.responseString(encoding: NSUTF8StringEncoding) {(res) -& Void in
if let strongSelf = weakSelf {
//do something
因为在block外使用弱引用(weakSelf),这个弱引用(weakSelf)指向的self对象,在block内捕获的是这个弱引用(weakSelf),而不是捕获self的强引用,也就是说,这就保证了self不会被block所持有。
那疑问就来了,为什么还要在block内使用强引用(strongSelf) ,因为,在执行block内方法的时候,如果self被释放了咋办,造成无法估计的后果(可能没事,也有可能出个诡异bug),为了避免问题发生,block内开始执行的时候,立即生成强引用(strongSelf),这个强引用(strongSelf) 指向了弱引用(weakSelf)所指向的对象(self对象),这样以来,在block内部实际是持有了self对象,人为地制造了暂时的循环引用。为什么说是暂时?是因为强引用(strongSelf) 的生命周期只在这个block执行的过程中,block执行前不会存在,执行完会立刻就被释放了。
强引用(strongSelf) 指向了弱引用(weakSelf)所指向的对象,等价于强引用了对象
下面这中不能解决循环引用
weak var weakSelf = self
_link = CADisplayLink(target: weakSelf!, selector: #selector(FPSLabel.tick(link:)))
_link.add(to: RunLoop.main, forMode: .commonModes)
it unwraps weakSelf when the CADisplayLink is initialized and passes a strong reference to self as the target.
我们为NSTimer/CADisplayLink对象指定target时候,虽然传入了弱引用,但是造成的结果是:强引用了弱引用所引用的对象,也就是最终还是强引用了对象,这和你直接传self进来效果是一样的。这样的做唯一作用是如果在CADisplayLink运行期间self被释放了,CADisplayLink的target也就置为nil,仅此而已。主题 : iOS CADisplayLink实现动画时出现内存问题,求大神看看
级别: 新手上路
可可豆: 85 CB
威望: 85 点
在线时间: 99(时)
发自: Web Page
来源于&&分类
iOS CADisplayLink实现动画时出现内存问题,求大神看看&&&
实现动画在arc开启时内存稳定。在arc关闭的时候内存每秒增加40m(看起来很害怕),不知道应该怎么改。求大神帮忙看看直接说代码吧 .h文件#import &UIKit/UIKit.h&@interface ViewController : UIViewController@property (strong, nonatomic) UIImageView * imgVA@property (strong, nonatomic) CADisplayLink * dispalyL@end.m文件#import &ViewController.h&#define IMAGECOUNT&&60@interface ViewController ()- (void)layoutUI;- (void)changeI- (NSArray *)imageFromG@end@implementation ViewController- (void)viewDidLoad {&&&&[super viewDidLoad];&&&&&&&&[self layoutUI];&&&&// Do any additional setup after loading the view, typically from a nib.}- (void)viewWillAppear:(BOOL)animated{&&&&[super viewWillAppear:animated];&&&&&&&&_dispalyLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(changeImage)];&&&&_dispalyLink.preferredFramesPerSecond = 24;&&&&[_dispalyLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];}- (void)viewWillDisappear:(BOOL)animated{&&&&[super viewWillDisappear:animated];&&&&[_dispalyLink removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];}- (void)layoutUI{&&&&_imgVAnimation = [[UIImageView alloc] initWithFrame:self.view.bounds];&&&&[self.view addSubview:_imgVAnimation];}- (void)changeImage{&&&&static NSUInteger indexOfImg = 0;&&&&//每秒执行24次if内语句&&&&&&&&UIImage *image = [self imageFromGroups][indexOfImg];&&&&&&&&_imgVAnimation.layer.contents = (id)image.CGI&&&&&&&&&&&&indexOfImg++;&&&&if (indexOfImg == IMAGECOUNT) {&&&&&&&&indexOfImg = 0;&&&&}}-(NSArray *)imageFromGroups{&&&&NSMutableArray *mArrImgForAnimation = [[NSMutableArray alloc] initWithCapacity:IMAGECOUNT];&&&&NSString *strImgN&&&&for (int i = 0; i & IMAGECOUNT; i++) {&&&&&& // NSString *qqq = [[NSBundle mainBundle] pathForResource:@&flowing_water1& ofType:@&jpg&];&&&&&&&&strImgName = [NSString stringWithFormat:@&flowing_water%d&,i+1];&&&&&&&&NSString * path = [[NSBundle mainBundle] pathForResource:strImgName ofType:@&jpg&];&&&&&&&&[mArrImgForAnimation addObject:[UIImage imageWithContentsOfFile:path]];&&&&}&&&&return mArrImgForA}- (void)didReceiveMemoryWarning {&&&&[super didReceiveMemoryWarning];&&&&// Dispose of any resources that can be recreated.}@end
级别: 新手上路
可可豆: 85 CB
威望: 85 点
在线时间: 99(时)
发自: Web Page
抱歉,问题是我粗心大意了。忘了没给array加autorelese;不过现在还有的问题时有时候动画会卡住暂停好长一会,然会在动,效果非常差!
关注本帖(如果有新回复会站内信通知您)
发帖、回帖都会得到可观的积分奖励。
按"Ctrl+Enter"直接提交
关注CocoaChina
关注微信 每日推荐
扫一扫 关注CVP公众号
扫一扫 浏览移动版iOS内存泄露的个人经验 - 简书
iOS内存泄露的个人经验
内存泄露解决分为了三步:1.静态分析:Instruments的Analyze。通过静态分析我们可以最初步的了解到代码的一些不规范的地方和一些代码逻辑上的错误;2.解决ViewController不释放的问题;3.Instruments的Leaks运行时分析内存泄露情况并解决;内存泄露:如果程序运行时一直分配内存而不及时释放无用的内存,程序占用的内存越来越大,直到把系统分配给该APP的内存消耗殚尽,程序因无内存可用导致崩溃,这样的情况我们称之为内存泄漏。可能引起的问题:1)内存消耗殆尽的时候,程序会因没有内存被杀死,即crash。2)当内存快要用完的时候,会非常的卡顿3)如果是ViewController没有释放掉,引起的内存泄露,还会引起其他很多问题,尤其是和通知相关的。没有被释放掉的ViewController还能接收通知,还会执行相关的动作,所以会引起各种各样的异常情况的发生。Analyze检测出的几种常见问题:使用Analyze能够发现一些代码不规范的地方。下面是我调试的过程中遇到的一些问题。报错1:
xxxxx ...... xxx
value stored to ‘width’during its initialization is never read。该问题的原因是:变量申请了内存并初始化了,但没有用使此变量,接着将此变量又重新赋值.- (CGSize)sizeForContent:(MGCMessageBaseEntity*)message {float width = size.width & 20 ? 20 : size.width + 5;width = size.width & MAX_CHAT_TEXT_WIDTH ? MAX_CHAT_TEXT_WIDTH : size.return CGSizeMake(width, size.height + 3);}规范的写法是:float width = size.width & MAX_CHAT_TEXT_WIDTH ? MAX_CHAT_TEXT_WIDTH : size.还有一种情况是:为同一个数据源分配了两块内存,这里不会引起内存泄露,因为为arr1分配的内存块虽然一直是空闲块,但是在生命周期结束时,这块内存会被释放掉。跟前面说的:
内存泄露是内存一直得不到释放,才会造成内存泄露 的情况 是 不一样,。NSArray *arr1 = [[NSArray alloc]init];if(index == 1){arr1 = self.usersA}else{arr1 = self.editA}因为self.usersArray和self.editArray都是被初始化过的数组,将它们赋值给了arr1,arr1又申请了内存。规范的写法是:NSArray *arr1;不为arr1分配内存。报错2.
xxxxx ...... xxx , Value stored to 'titleString' is never read该变量从来没有被使用报错3. xxxxx ...... xxx
,Potential leak of an object allocated on line 101 and stored into '' 潜在的内存泄露:这里主要是一些非OC对象,ARC不会对它进行释放,所以造成了一直没有释放。比如一些类型:CGImageRef(对应调用CGImageRelease)、CGContextRef(对应调用CGContextRelease)CGColorSpaceRef(对应CGColorSpaceRelease) 这些都是非OC对象,所以要自己记着释放掉。// 关于ViewController 不释放 问题描述ViewController不释放,会导致很多问题,我说一下我遇到的情况:我做的是一个电商APP,我做了一个 系统公告 功能,发布 系统消息 时会发送@all消息。当我做完了 系统消息 公告,发了一个 系统消息 试试,结果,消息群发了,发到了好几个聊天会话中去了。最后查出是 因为 chattingViewController 没有释放掉,发送@all消息的通知,那些没有被释放掉的chattingViewController都收到了,都执行了发送@all消息的动作,所以导致很多会话都发送了@all消息。我还做一个 此用户没有资格开通VIP会员的 的功能,点击 开通VIP 进入到 付款页面的
的时候,之前的 开通VIP主页面 都没有被释放,没有资格开通VIP 会发一个通知,显示一个alert:你没有资格开通 VIP 。多次点击开通,就会创建多个主界面,多个主界面都会收到这个通知,于是就显示了多个alertView。NSTimer,NSTimer会对它的target持有强引用,如果NSTimer不释放掉,就会一直持有它的target的强引用,会一直都释放不掉,造成内存泄露。二、解决方法想要知道ViewController有没有被释放,一个方法就是可以通过看ViewController有没有执行dealloc方法。大概有几个地方,比较容易引起内存泄露循环引用:最多的就是block引起的循环引用。(1)某个类将block作为自己的属性变量,然后该类在block的方法体里面又使用了该类本身;相互持有,导致都释放不了。 代码例子: [self.tableViewmas_makeConstraints:^(MASConstraintMaker *make) { make.left.right.equalTo(self.view); make.top.equalTo(self.navigationBar.mas_bottom); make.bottom.equalTo(self.view); }]; 修改为: __weaktypeof(self) weakSelf = 块内的self,换成weakSelf就行了。 block不是self的属性或者变量时,在block内使用self不会循环引用; (2)如果块是一个单例持有的,块内又使用了ViewController这个类,会引起循环引用。
[[OutsidePacketsSchedule shareInstance] sendParameters:dict requestCmd:@"addCustomEmoReq"responseCmd:@"addCustomEmoRsp"complete:^(idresponse,NSError*error) {if(!error){
[weakSelf.viewsetToast:@"添加自定义表情成功"]; } }]; 上例中的单例持有的代码块中要用弱引用,原因是:单例不会被释放掉,它会一直持有block,导致该block所在的ViewController释放不掉。 (3)如果是方法中的参数是block,不会造成循环引用,因为方法中的block是位于栈内存的,方法返回后,block将会无效。还有就是 NSTimer和CADisplayLink这种;+ (NSTimer*)scheduledTimerWithTimeInterval:(NSTimeInterval)ti
target:(id)aTarget
selector:(SEL)aSelector userInfo:(nullableid)userInfo
repeats:(BOOL)yesOrN{}从文档中方法的定义上可以看到,NSTimer是会强引用它的target的,像其他的delegate一般都是weak的,所以这里比较特殊。NSTimerClass Reference是这样对target描述的:The object to which to send the message specified by aSelector when the timer fires. The timer maintains astrongreference to target until it (the timer) is invalidated.NSTimerClass Reference还指出: Runloop会强引用timer,因为如果一个timer是循环的,如果没被强引用,那么在函数返回后,则会被销毁,就不能循环地通知持有的target。所以NSTimer是被放到Runloop中执行的。如果我们不调用invalidate timer,runloop就会一直持有timer,而timer也一直持有ViewController,这样就会造成内存泄露。解决这类问题的方法就是:在不需要NSTimer的时候,及时调用[self.timer
invalidate]。千万不要在dealloc方法中调用,因为NSTimer强引用self,所以不会执行dealloc方法。另外就是 delegate,一般是weak的情况分析;对象之间的循环引用:例子:两个ViewController都需要使用对方,这个时候可以用@ 需要说明的是 在 .h 中引入某个类, @class 指的是 当前文件 只是引入类名, 并没有使用类里面的东西. 想要在 .m 里面使用 类的内容的话, 还是要 #import &&, 这种情况跟 上面的对象之间的防止循环引 有点不一样.最后一个大招: 混编时, 注意老代码 有没有开启 ARC, 没有开启的话就等着 乌龙吧! 如果当你把 ViewController 里的每行代码都分析了,强引用的地方都解决了,还是不执行dealloc方法,纠结了好久, 头发都挠掉了 n 多根,那你就该去找找 ViewController 有没有开启ARC,也许之前的代码局势 MRC 模式, 但是也有可能不知道是被那个队友给关闭了......
内存泄露解决分为了三步: 1.静态分析:Instruments的Analyze。通过静态分析我们可以最初步的了解到代码的一些不规范的地方和一些代码逻辑上的错误; 2.解决ViewController不释放的问题; 3.Instruments的Leaks运行时分析内存泄露情况...
一、问题描述 ViewController不释放,会导致很多问题,我举几个我遇到的例子。 我做的是一个企业即时通讯APP,我做了一个群公告功能,发布群公告时会发送@all消息。某天,我做完了群公告,发了一个群公告试试,结果,消息群发了,发到了好几个聊天会话中去了。因为cha...
父类实现深拷贝时,子类如何实现深度拷贝。父类没有实现深拷贝时,子类如何实现深度拷贝。o 深拷贝同浅拷贝的区别:浅拷贝是指针拷贝,对一个对象进行浅拷贝,相当于对指向对象的指针进行复制,产生一个新的指向这个对象的指针,那么就是有两个指针指向同一个对象,这个对象销毁后两个指针都应...
iOS可能存在的内存泄露: block 循环引用。当一个对象有一个block属性,而block属性又引用这个对象本身那么要造成循环引用。这个时候就用___weak声明下对象,用对象的弱引用指针。 头文件相互包含。那么先在.h文件用前向引用声明,@class(类名);然后在....
前言 要讲关于iOS里的内存泄露,那就需要了解一下iOS的内存管理机制。现在基本上我们使用的是ARC机制,在iOS5之前内存管理是MRC机制。MRC秉承着‘谁创建,谁释放,谁引用,谁管理’的理念来管理内存,所以那个时代的iOS程序员还是比较苦逼的,一不小心就导致内存泄露或过...
不少人有这个毛病,有时候工作繁忙,不能按时吃饭或者吃不上饭,就会出现胃痛的症状,十分难受,也不了解为什么会这样,认为只是饿的,等到吃完饭就好了,于是就一直忍着。 究其原因,人在饥饿时,空虚的胃内分泌大量胃液,因没有与食物混合而直接进入十二指肠,假如十二指肠球部存在溃疡的话,...
一、一分钟目标 1、制定目标容易出现的问题 常见问题:经理人制定的是目标A,但员工做的是事情B 目标不应该是领导给员工单方面布置的,一个目标的制定过程,应该是经理人和下属、同事一起商讨达成一致的。 2、好目标的三个要素 一个好的目标要包括以下三部分内容: 明确目标内容 明确...
生活中总是会面临各种各样的选择,站在选择的十字路口时,我们总是习惯于对身边的人提问,我该怎么选择? 到底是向左走还是向右走? 1 靓哥大学毕业的时候,全球经济尚处于低迷状态,就业前景也并不乐观。好在他学的是国内炙手可热的土木工程专业,自身条件优秀,所以还算顺利地拿到了两个o...
我要寄个快递。 因为寄的东西比较多,想要找个便宜省事的。小区门口常盘踞着各家快递小哥,我决定去询价。先过去问了中通的小哥,了解价格后我觉得有点小贵,但还是先留了电话,约定了有需要会给他电话。然后去了超市买行李袋,没有径直去问在一边的圆通小哥,因为他正忙着派件,也可能因为中通...
在意的事情太多,就会没有着重点。而这些事也大多没有留下太多的痕迹。 一个人的行走,应该会唤起心里的自己。 认真想想这一年多来,确实是悔恨多于成长。而现在发现自己的困顿之处,一切应该都不太晚。 没有自我,太在意他人的想法,让自己错失了太多可以变好的机会。而独立人格最需要的应该...UIImageView 和 CADisplayLink 实现 Tom 汤姆猫动画效果的区别 - 简书
UIImageView 和 CADisplayLink 实现 Tom 汤姆猫动画效果的区别
(1)UIImageView 的动画操作,来自定义循环播放动画(不建议使用,内存消耗大)
(2)CADisplayLink 是一个计时器,但是同 NSTimer 不同的是,CADisplayLink 的刷新周期同屏幕完全一致。
例如在 iOS 中屏幕刷新周期是60次/秒,CADisplayLink 刷新周期同屏幕刷新一致也是60次/秒,这样一来使用它完成的逐帧动画(又称为“时钟动画”)完全感觉不到动画的停滞情况。
ViewController.h
#import &UIKit/UIKit.h&
@interface ViewController : UIViewController
@property (strong, nonatomic) UIImageView *imgVA
@property (strong, nonatomic) CADisplayLink *displayL
#import "ViewController.h"
@interface ViewController ()
- (void)layoutUI;
- (void)changeI
- (void)layoutUINoS
- (NSArray *)imagesFromG
- (NSArray *)imagesFromFolderR
@implementation ViewController
#define kImgCount 29
- (void)viewDidLoad {
[super viewDidLoad];
//[self layoutUINoSuggest];
[self layoutUI];
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
//开始动画;对应使用[self layoutUINoSuggest]的情况
//[_imgVAnimation startAnimating];
//实例化时钟对象
_displayLink=[CADisplayLink displayLinkWithTarget:self selector:@selector(changeImage)];
//添加时钟对象实例到主运行循环
[_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
//停止动画;对应使用[self layoutUINoSuggest]的情况
//[_imgVAnimation stopAnimating];
//从主运行循环移除时钟对象实例
[_displayLink removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
#pragma mark - 推荐使用的方式
使用CADisplayLink,来自定义循环播放动画(推荐使用,内存消耗小)
CADisplayLink是一个计时器,但是同NSTimer不同的是,CADisplayLink的刷新周期同屏幕完全一致。例如在iOS中屏幕刷新周期是60次/秒,CADisplayLink刷新周期同屏幕刷新一致也是60次/秒,这样一来使用它完成的逐帧动画(又称为“时钟动画”)完全感觉不到动画的停滞情况
- (void)layoutUI {
_imgVAnimation = [[UIImageView alloc] initWithFrame:self.view.bounds];
[self.view addSubview:_imgVAnimation];
- (void)changeImage {
//定义一个变量记录执行次数
static NSUInteger s=0;
static NSUInteger indexOfImg = 0;
//每秒执行12次if内的语句;分别当s=5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60...
if (s % 5 == 0) {
UIImage *image=[self imagesFromGroups][indexOfImg];
_imgVAnimation.layer.contents=(id)image.CGI //更新图片
indexOfImg++;
if (indexOfImg == kImgCount) {
indexOfImg = 0;
#pragma mark - 不建议使用的方式
使用图片视图的动画操作,来自定义循环播放动画(不建议使用,内存消耗大)
- (void)layoutUINoSuggest {
_imgVAnimation = [[UIImageView alloc] initWithFrame:self.view.bounds];
_imgVAnimation.animationImages = [self imagesFromGroups]; //引用图片数组,导致一次性加载图片数组,内存消耗大
//设置动画持续时间(图片播放周期时间,而不是播放一张图片的时间);单位为秒;默认值为每秒30帧(每秒播放30张图片)
_imgVAnimation.animationDuration = 3;
//设置动画播放重复次数;默认值为0,表示无限循环
_imgVAnimation.animationRepeatCount = 0;
[self.view addSubview:_imgVAnimation];
#pragma mark - 读取图片文件数组操作
获取来自分组(黄色文件夹)的图片数组;图片文件路径不需要包含文件夹
使用右键“Add Files to...”-&“Added folders” : “Create groups”,生成分组(黄色文件夹)
@return 来自分组(黄色文件夹)的图片数组
- (NSArray *)imagesFromGroups {
NSMutableArray *mArrImgForAnimation = [[NSMutableArray alloc] initWithCapacity:kImgCount];
NSString *strImgN
for (NSUInteger i=0; i&kImgC i++) {
strImgName = [NSString stringWithFormat:(i&10 ? @"Happy000%lu" : @"Happy00%lu")
, (unsigned long)i];
//[mArrImgForAnimation addObject:[UIImage imageNamed:strImgName]]; //[UIImage imageNamed:strImgName]会缓存图片,这里图片多,占内存过大,不建议用
//读取方式一(推荐使用):
NSString *path = [[NSBundle mainBundle] pathForResource:strImgName ofType:@"jpg"];
//NSString *path = [[NSBundle mainBundle] pathForResource:strImgName ofType:nil]; //这种方式的话,strImgName的格式就为“xx.jpg”
//读取方式二:
//NSString *path = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:strImgName];
//为数组mArrImgForAnimation添加数组元素
[mArrImgForAnimation addObject:[UIImage imageWithContentsOfFile:path]]; //虽然没缓存图片,但也可能存在内存泄露问题
return mArrImgForA
获取来自文件夹引用(蓝色文件夹)的图片数组;图片文件路径需要包含文件夹
使用右键“Add Files to...”-&“Added folders” : “Create folder references”,生成文件夹引用(蓝色文件夹)
@return 来自文件夹引用(蓝色文件夹)的图片数组
- (NSArray *)imagesFromFolderReferences {
NSMutableArray *mArrImgForAnimation = [[NSMutableArray alloc] initWithCapacity:kImgCount];
NSString *strImgN
for (NSUInteger i=0; i&kImgC i++) {
strImgName = [NSString stringWithFormat:(i&10 ? @"Happy000%lu" : @"Happy00%lu")
, (unsigned long)i];
//读取方式一(推荐使用):
NSString *path = [[NSBundle mainBundle] pathForResource:strImgName ofType:@"jpg" inDirectory:@"TomCat"];
//NSString *path = [[NSBundle mainBundle] pathForResource:strImgName ofType:nil inDirectory:@"TomCat"]; //这种方式的话,strImgName的格式就为“xx.jpg”
//读取方式二:
//NSString *bundlePath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"TomCat"];
//NSString *path = [bundlePath stringByAppendingPathComponent:strImgName];
//为数组mArrImgForAnimation添加数组元素
[mArrImgForAnimation addObject:[UIImage imageWithContentsOfFile:path]]; //虽然没缓存图片,但也可能存在内存泄露问题
return mArrImgForA
星光定当照亮黑暗,才不负仰望。
在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥ios动画全貌。在这里你可以看到iOS中如何使用图层精简非交互式绘图,如何通过核心动画创建基础动画、关键帧动画、动画组、转场动画,如何通过UIView的装饰方法对这些动画操作进行简化等。在今...
在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥iOS动画全貌。在这里你可以看到iOS中如何使用图层精简非交互式绘图,如何通过核心动画创建基础动画、关键帧动画、动画组、转场动画,如何通过UIView的装饰方法对这些动画操作进行简化等。在今...
大家都知道在iOS中实现一个动画相当简单,只要调用UIView的块代码即可实现一个动画效果,这在其他系统开发中基本不可能实现。下面通过一个简单的UIView进行一个图片放大动画效果演示: 使用上面UIView封装的方法进行动画设置固然十分方便,但是具体动画如何实现我们是不清...
一、CoreAnimation(核心动画) 1.核心动画介绍 1.什么是核心动画 Core Animation可以用在 Mac OS X 和 iOS平台. Core Animation的动画执行过程是在后台操作的.不会阻塞主线程. 要注意的是, Core Animation...
发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注
09:45字数 61697阅读 3316评论 2喜欢 85 用到的组件 1、通过CocoaPods安装 项目名称 项目信息 AFNetworking 网络请求组件 FM...
这是我第一次这么认真的,为了感悟而去感悟一本书,为了成长而去从一本书中汲取营养。这是一部很出名的儿童教育著作,我也早有所耳闻,读之前我是怀着虔诚的心情的,读之后的心情,却更加虔诚。巴学园的这种教育理念近乎一种信仰,与小林先生如此,与我们每个即将从事儿童教育的人都应如此。 这...
不久前,当地时间3月26日晚,一位56岁的中国公民在巴黎被法国警察枪杀。 这两天美联航亚裔乘客受辱的新闻又引起了众怒。美国联合航空周日一班由芝加哥飞往肯塔基州路易斯威尔,编号为UA3411的航班,因超额订票而将一名不愿下机的亚裔乘客强行拖走,这名乘客在被拖走时眼镜脱落,面有...
一个错误要很长时间去弥补 就像一个谎言 需要更多的谎言去圆 在之前 由于一不小心我弄丢了400元 虽然不多 但对于我这种每周都从父母那要钱的来说 真的一下凑不了那么多 可是我不敢对父母说 只好向同学借 以至于后来我每周要比原来多要100 终于一个月下来 我可以还清所借债 起...
投资日记(日) 持续不断的朝核危机还在继续发展,上周伦敦金突破了关键阻力位1260,目前已经离1300一步之遥,即将解放2013年在1350被套的中国大妈,在即将解放前,我对几个投资品简单说几句看法。 1:股票 中国股市就是个笑话,铁公鸡一毛不拔公司比比皆...
今天在微信公众号“国学文化”里看到一篇题为《董卿的爸爸为啥不让她打扮?这位父亲的回答亮了!》的文章。作者借“董卿”的事例还有其一个叔叔家的漂亮女儿求学成才的过程,阐述了两位家长为何不让漂亮的女儿打扮自己,甚至说女儿不漂亮,看完文章后深有同感。 作者在文中阐述的观点是,如果漂...}

我要回帖

更多关于 手机怎么扩展内存128g 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信