NStimer使用要点之必备知识点二

来源:互联网 发布:签证邀请函知乎 编辑:程序博客网 时间:2024/06/05 21:51

一 . objc_msgSend苹果官方文档的介绍

先看官方文档的Quick Help,逐字翻译后,后面会有代码对这些令人boring的文档进行解释:

Declaration: id objc_msgSend(id self, SEL op, …);

Description: Sends a message with a simple return value to an instance of a class.

  • 向类的实例发送一个简单返回值的消息

When it encounters a method call, the compiler generates a call to one of the functions objc_msgSend, objc_msgSend_stret, objc_msgSendSuper, or objc_msgSendSuper_stret.

  • 当遇到方法调用时,编译器会生成一个调用函数objc_msgSend,objc_msgSend_stret,objc_msgSendSuper或objc_msgSendSuper_stret。

Messages sent to an object’s superclass (using the super keyword) are sent using objc_msgSendSuper; other messages are sent using objc_msgSend.

  • 使用objc_msgSendSuper发送“发送到对象的超类(使用super关键字)”的消息;
    其他消息使用objc_msgSend发送。

Methods that have data structures as return values are sent using objc_msgSendSuper_stret and objc_msgSend_stret.

  • 将数据结构作为返回值的方法使用objc_msgSendSuper_stret和objc_msgSend_stret发送。

* Parameters:*
- self
A pointer that points to the instance of the class that is to receive the message.
- op
The selector of the method that handles the message.
- …
A variable argument list containing the arguments to the method.

一 方法调用的三种模式:
1. 直接调用
2. performSelector
3. 消息机制

//    Person *p = [[Person alloc]init];//    1.OC调用的基本方式--直接调用//    [p eat];//    2.performSelector方式调用,编译时不会发现eat方法没有声明,运行时崩溃//    if ([p respondsToSelector:@selector(eat)])//    {//        [p performSelector:@selector(eat)];//    }//    3.消息发送--消息机制//    Xcode5.0之后,苹果官方不建议大家使用底层代码,而是使用运行时//    objc_msgSend();同时如果要测试这个功能的话最好设置以下为No:![build setting中搜索msg关键词,设置为No](http://img.blog.csdn.net/20170829113146474?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvWkxKOTI1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)//    3.1分步骤实现//    Person * p  =objc_msgSend(<#id self#>, <#SEL op, ...#>)//    Person * p = [Person alloc];//    Person * p  = objc_msgSend([Person class], @selector(alloc));//    p=[p init];//    p = objc_msgSend(p, @selector(init));//    3.2 合并实现    Person *p;    p = objc_msgSend(objc_msgSend(objc_getClass("Person"), sel_registerName("alloc")), sel_registerName("init"));    objc_msgSend(p, @selector(eat));

平时所写的OC代码,运行的时候都转化为Runtime的C语言代码。

二. NStimer的使用
(扩展自http://www.jianshu.com/p/3ccdda0679c1)
先看下Foundation框架下NSTimer.h文件暴露给我的内容:
6个类方法
4个实例方法
5个属性

/*  NSTimer.h    Copyright (c) 1994-2016, Apple Inc. All rights reserved.*/#import <Foundation/NSObject.h>#import <Foundation/NSDate.h>NS_ASSUME_NONNULL_BEGIN@interface NSTimer : NSObject+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;> *第一个类方法官文描述*:You must add the new timer to a run loop, using addTimer:forMode:. Then, after ti have elapsed, the timer fires, invoking invocation. (If the timer is configured to repeat, there is no need to subsequently re-add the timer to the run loop.)> 上面的话意思很明确,简单直白,奉上翻译:> 您必须使用addTimer:forMode:添加新的计时器到运行循环。然后,在ti过后,定时器触发,触发调用。 (如果定时器配置为重复,则不需要随后将定时器重新添加到运行循环。)>  Use the `timerWithTimeInterval:invocation:repeats:` or `timerWithTimeInterval:target:selector:userInfo:repeats:`class method to create the timer object without scheduling it on a run loop. //翻译下这句话, 使用上述两个timer开头的类方法来创建定时器对象,但是没有添加到运行循环(without scheduling it on a run loop),而是需要程序员在创建定时器后手动的调用 NSRunLoop 对象的 addTimer:forMode: 方法。----------+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;> *第二个类方法官文描述*:> Creates and returns a new NSTimer object and schedules it on the current run loop in the default mode.After ti seconds have elapsed, the timer fires, invoking invocation.> 创建并返回一个新的NSTimer对象,并以默认模式在当前运行循环中进行调度。经过ti秒之后,定时器触发,触发调用tips:上述两个方法中都有参数invocation,官文解释如下,这个有时间再做研究:> The invocation to use when the timer fires. The invocation object maintains a strong reference to its arguments until the timer is invalidated.> 计时器触发时使用的调用。调用对象保持对其参数的强引用,直到定时器无效。----------+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;> *第三个类方法官文描述*:同第一个类方法(都是timerWith...开头的)都需要程序员在创建定时器后手动的调用 NSRunLoop 对象的 addTimer:forMode: 方法。> 我们平时使用较多的就是这个和第四个类方法来创建定时器。> 同时,相比第一个方法多了一个参数target和selector,我们看下官文描述:**Parameters:**  targetThe object to which to send the message specified by aSelector when the timer fires. The timer maintains a strong reference to this object until it (the timer) is invalidated.> 定时器触发时由aSelector指定的消息发送的对象。定时器保持对该对象的强引用,直到它(定时器)无效为止。**aSelector:**The selector should have the following signature: timerFireMethod: (including a colon to indicate that the method takes an argument). The timer passes itself as the argument, thus the method would adopt the following pattern:
  • (void)timerFireMethod:(NSTimer *)timer
> 选择器应该具有以下签名:timerFireMethod :(包括一个冒号表示该方法接受参数)。定时器自身作为参数,因此该方法将采用以下模式:
  • (void)timerFireMethod:(NSTimer *)timer
----------> *第四个类方法官文描述*:同第二个类方法(以scheduledTimerWith...开头),创建并返回一个新的NSTimer对象,并以‘默认模式’在当前运行循环中进行调度。+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;----------第五/六个类暂时不可自行翻译。文档如下:> *第五个类方法官文描述*:/// Creates and returns a new NSTimer object initialized with the specified block object./// - parameter:  timeInterval  The number of seconds between firings of the timer. If seconds is less than or equal to 0.0, this method chooses the nonnegative value of 0.1 milliseconds instead/// - parameter:  repeats  If YES, the timer will repeatedly reschedule itself until invalidated. If NO, the timer will be invalidated after it fires./// - parameter:  block  The execution body of the timer; the timer itself is passed as the parameter to this block when executed to aid in avoiding cyclical references+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block ----------> *第六个类方法官文描述*:/// Creates and returns a new NSTimer object initialized with the specified block object and schedules it on the current run loop in the default mode./// - parameter:  ti    The number of seconds between firings of the timer. If seconds is less than or equal to 0.0, this method chooses the nonnegative value of 0.1 milliseconds instead/// - parameter:  repeats  If YES, the timer will repeatedly reschedule itself until invalidated. If NO, the timer will be invalidated after it fires./// - parameter:  block  The execution body of the timer; the timer itself is passed as the parameter to this block when executed to aid in avoiding cyclical references+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block ----------以下为实例方法,主要介绍第三个,`- (void)fire;`----------> *第一个实例方法官文描述*:/// Initializes a new NSTimer object using the block as the main body of execution for the timer./// - parameter:  fireDate   The time at which the timer should first fire./// - parameter:  interval  The number of seconds between firings of the timer. If seconds is less than or equal to 0.0, this method chooses the nonnegative value of 0.1 milliseconds instead/// - parameter:  repeats  If YES, the timer will repeatedly reschedule itself until invalidated. If NO, the timer will be invalidated after it fires./// - parameter:  block  The execution body of the timer; the timer itself is passed as the parameter to this block when executed to aid in avoiding cyclical references> *第二个实例方法官文描述*:- (instancetype)initWithFireDate:(NSDate *)date interval:(NSTimeInterval)ti target:(id)t selector:(SEL)s userInfo:(nullable id)ui repeats:(BOOL)rep > 默认的初始化方法,(创建定时器后,手动添加到 运行循环,并且手动触发才会启动定时器)> Causes the receiver’s message to be sent to its target.You can use this method to fire a repeating timer without interrupting its regular firing schedule. If the timer is non-repeating, it is automatically invalidated after firing, even if its scheduled fire date has not arrived.>假设实例化了一个定时器,NSTimeInterval设置的为10,那么程序运行后10s后开始执行selector方法,但是,如果调用了fire方法,程序运行起来就执行selector方法,不会等到十秒后。- (void)fire;@property (copy) NSDate *fireDate;@property (readonly) NSTimeInterval timeInterval;// Setting a tolerance for a timer allows it to fire later than the scheduled fire date, improving the ability of the system to optimize for increased power savings and responsiveness. The timer may fire at any time between its scheduled fire date and the scheduled fire date plus the tolerance. The timer will not fire before the scheduled fire date. For repeating timers, the next fire date is calculated from the original fire date regardless of tolerance applied at individual fire times, to avoid drift. The default value is zero, which means no additional tolerance is applied. The system reserves the right to apply a small amount of tolerance to certain timers regardless of the value of this property.// As the user of the timer, you will have the best idea of what an appropriate tolerance for a timer may be. A general rule of thumb, though, is to set the tolerance to at least 10% of the interval, for a repeating timer. Even a small amount of tolerance will have a significant positive impact on the power usage of your application. The system may put a maximum value of the tolerance.// Setting a tolerance for a timer allows it to fire later than the scheduled fire date, improving the ability of the system to optimize for increased power savings and responsiveness. The timer may fire at any time between its scheduled fire date and the scheduled fire date plus the tolerance. The timer will not fire before the scheduled fire date. For repeating timers, the next fire date is calculated from the original fire date regardless of tolerance applied at individual fire times, to avoid drift. The default value is zero, which means no additional tolerance is applied. The system reserves the right to apply a small amount of tolerance to certain timers regardless of the value of this property.// As the user of the timer, you will have the best idea of what an appropriate tolerance for a timer may be. A general rule of thumb, though, is to set the tolerance to at least 10% of the interval, for a repeating timer. Even a small amount of tolerance will have a significant positive impact on the power usage of your application. The system may put a maximum value of the tolerance.// 这是7.0之后新增的一个属性,因为NSTimer并不完全精准,通过这个值设置误差范围@property NSTimeInterval tolerance NS_AVAILABLE(10_9, 7_0);> 停止(invalidate) Timer ---> 唯一的方法将定时器从循环池中移除> You must call this method before releasing a port object (or removing strong references to it if your application is garbage collected).一定要记得在页面消失(返回上一层级)的时候,提前(在viewWillDisappear或者viewDidDisappear中,最好不要在dealloc或者deinit中invalidate,如果在这里做,注意不要让循环强引用问题产生)invalidate定时器,否则的话页面不释放,造成内存泄漏。切记!!!- (void)invalidate;- @property (readonly, getter=isValid) BOOL valid;@property (nullable, readonly, retain) id userInfo;@endNS_ASSUME_NONNULL_END

综上所述:
1、参数repeats是指定是否循环执行,YES将循环,NO将只执行一次。
2、timerWithTimeInterval 这两个类方法创建出来的对象如果不用 addTimer: forMode方法手动加入主循环池中,将不会循环执行。
3、scheduledTimerWithTimeInterval 这两个方法会将定时器添加到当前的运行循环,运行循环的模式为默认模式。
4、init方法需要手动加入循环池,它会在设定的启动时间启动。

來源:简书 链接:http://www.jianshu.com/p/3ccdda0679c1

原创粉丝点击