1.CGRectGet**方法
CGRectGet**
共有如下8个方法, 用于对一个Rect进行处理;
方法 | 描述 |
---|---|
CGRectGetMaxX | 矩形的右边距 |
CGRectGetMaxY | 矩形下边距 |
CGRectGetMidX | 矩形中心点横坐标 |
CGRectGetMidY | 矩形中心点纵坐标 |
CGRectGetMinX | 矩形左边距 |
CGRectGetMinY | 矩形上边距 |
CGRectGetWidth | 矩形宽度 |
CGRectGetHeight | 矩形高度 |
2.instancetype 和id
instancetype 和id的区别有如下三个:
- instancetype在类型表示上,跟id一样,可以表示任何对象类型
- instancetype只能用在返回值类型上,不能像id一样用在参数类型上
- instancetype比id多一个好处:编译器会检测instancetype的真实类型(方法所在类的类型)
通过参考文献可以了解到,这是一个针对编译器的trick. 我们通常在编写一个类的时候,免不了编写返回为当前类对象的类,例如copy, init等方法. 如果这些方法返回类型直接指定为id, 则在使用的时候编译器不能确定你的返回值具体是什么类型, 因而会跳过一些必要的检查. instancetype 就是为了避免这种情况发生而产生的.
参考
3.View 动画
-
animateWithDuration
animateWithDuration
为view的属性变化添加动画, 其声明方式:animateWithDuration:animations: animateWithDuration:animations:completion: animateWithDuration:delay:options:animations:completion:
可以改变的属性包括
frame
,bounds
,center
,transform
,alpha
,backgroundColor
,contentStretch
;- (IBAction)showHideView:(id)sender
{
// Fade out the view right away
[UIView animateWithDuration:1.0
delay: 0.0
options: UIViewAnimationOptionCurveEaseIn
animations:^{
thirdView.alpha = 0.0;
}
completion:^(BOOL finished){
// Wait one second and then fade in the view
[UIView animateWithDuration:1.0
delay: 1.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
thirdView.alpha = 1.0;
}
completion:nil];
}];
}
```
通过上面的例子,我们能够知道:
* 1)animateWithDuration方法是属于UIView 的类方法;
* 2)在animations:后面的block中对view的设置即动画结束时的状态, 方法会自动计算中间过程;
从文档中,我们可以知道:
* 3)动画代码在另一个线程中执行;
* 4)当动画在执行过程中,如果某个view的属性被修改了,并不会影响动画的执行, 其处理方式是当前动画继续执行,并且以动画会调整到以新设置的属性为最终状态来变化;
* 5)如果想要重复执行多次, 可以通过重复次数加0.5的方式使其停留在最终状态;
[关于4) 5)的demo](https://github.com/talkfiled/resources/tree/master/codes/animation/animation)
除了改变一个View的属性值, 某些情况下还想控制两个view之间的切换动画, 可以通过如下两个方法实现view间的切换:
transitionWithView
- (IBAction)displayNewPage:(id)sender
{
[UIView transitionWithView:self.view
duration:1.0
options:UIViewAnimationOptionTransitionCurlUp
animations:^{
currentTextView.hidden = YES;
swapTextView.hidden = NO;
}
completion:^(BOOL finished){
// Save the old text and then swap the views.
[self saveNotes:temp];
UIView* temp = currentTextView;
currentTextView = swapTextView;
swapTextView = temp;
}];
}
如上代码实现了两个view currentTextView
和swapTextView
之间的 向上翻页切换效果, 翻页范围self.view
也就是说 transitionWithView
的用于切换某个view下两个子类;
transitionFromView
transitionFromView
的一个使用方法如下,
- (IBAction)displayNewPage:(id)sender
{
[UIView transitionWithView:self.view
duration:1.0
options:UIViewAnimationOptionTransitionCurlUp
animations:^{
currentTextView.hidden = YES;
swapTextView.hidden = NO;
}
completion:^(BOOL finished){
// Save the old text and then swap the views.
[self saveNotes:temp];
UIView* temp = currentTextView;
currentTextView = swapTextView;
swapTextView = temp;
}];
}
与transitionWithView
相同transitionFromView
也实现了两个view之间的切换, 不同的是, transitionWithView
需要指定一个父view 实现view之间的切换,而transitionFromView
不需要;
经过测试transitionFromView
的切换范围为FromView的父控件, 即:每次切换的刷新(变化,例如翻页的范围)范围为其父view
切换效果
动画效果 | 描述 |
---|---|
UIViewAnimationOptionLayoutSubviews | cell2 |
UIViewAnimationOptionAllowUserInteraction | cell2 |
UIViewAnimationOptionBeginFromCurrentState | cell2 |
UIViewAnimationOptionRepeat | cell2 |
UIViewAnimationOptionAutoreverse | cell2 |
UIViewAnimationOptionOverrideInheritedDuration | cell2 |
UIViewAnimationOptionOverrideInheritedCurve | cell2 |
UIViewAnimationOptionAllowAnimatedContent | cell2 |
UIViewAnimationOptionShowHideTransitionViews | cell2 |
UIViewAnimationOptionOverrideInheritedOptions | cell2 |
UIViewAnimationOptionCurveEaseInOut | cell2 |
UIViewAnimationOptionCurveEaseIn | cell2 |
UIViewAnimationOptionCurveEaseOut | cell2 |
UIViewAnimationOptionCurveLinear | cell2 |
UIViewAnimationOptionTransitionNone | cell2 |
UIViewAnimationOptionTransitionFlipFromLeft | cell2 |
UIViewAnimationOptionTransitionFlipFromRight | cell2 |
UIViewAnimationOptionTransitionCurlUp | cell2 |
UIViewAnimationOptionTransitionCurlDown | cell2 |
UIViewAnimationOptionTransitionCrossDissolve | cell2 |
UIViewAnimationOptionTransitionFlipFromTop | cell2 |
UIViewAnimationOptionTransitionFlipFromBottom | cell2 |
参考
4.随机数生成
iOS 开发中可以通过如下四种方法获取随机数:
-
rand
rand
是标准c库中的一个方法, 根据一个seed返回一个范围在[0 - RAND_MAX]的随机数列(伪随机).
srand 用于设定当前seed的值int main(void)
{
srand((unsigned int)time(0));; //将当前时间用作随机生成器种子
int random_variable = rand();
printf("Random value on [0,%d]: %d\n", RAND_MAX, random_variable);
}
```
-
random
random
也是标准c库中的方法, 用于返回一个返回再[0 - (2**31)-1]之间的随机数列(伪随机).
与rand
相比,random
更加随机,
int main(void)
{
srandom((unsigned int)time(0));; //将当前时间用作随机生成器种子
int random_variable = random();
}
```
3. `arc4random`
`arc4random`采用arc4加密的密钥流发生器(key stream generator employed by the arc4 cipher) 返回一个范围在[0 - (2**32)-1]之间的随机数列(伪随机).
```objc
int main(void)
{
// 不需要设置种子
int random_variable = arc4random();
}
```
4. `arc4random_uniform(u_int32_t upper_bound)`
`arc4random_uniform(u_int32_t upper_bound)`返回一个[0-upper_bound]之间的伪随机数列;
#### 参考
[arc4random](https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man3/arc4random_uniform.3.html)
[srand](https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man3/rand.3.html#//apple_ref/doc/man/3/rand)
## 状态栏样式控制
`preferredStatusBarStyle ` view controller的方法, 用于指定状态栏的样式;
想要修改状态栏样式,可以通过重写该方法并返回对应的值. 有两个值可用:
* UIStatusBarStyleDefault: 深色样式, 当浅色背景时用;
* UIStatusBarStyleLightContent: 浅色样式, 深色背景时用;
## ios 方法大集合
#### kvc
KVC(Key-value coding)键值编码, 指的是IOS开发中,可以允许开发者通过Key名直接访问对象的属性, 或者给对象的属性复制. 而不需要调用明确的存取方法. 这样就可以在运行时修改对象的属性值,而不需要编译时确定;
重要的方法:
1. kvc 常用重要方法
kvc 编程都是对NSObject 对象的扩展实现的, 因此所有继承制NSobject的类型都可以使用kvc;以下四个重要方法揭示了kvc编程的核心思想:
-
(nullable id)valueForKey:(NSString *)key;
//通过Key来取值 -
(void)setValue:(nullable id)value forKey:(NSString *)key;
//通过Key来设值 -
(nullable id)valueForKeyPath:(NSString *)keyPath;
//通过KeyPath来取值 -
(void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;
//通过KeyPath来设值
前两个方法揭示了kvc的核心思想, 即通过一个字符串 key来给对象赋值value,或者取出对象中的值;
后两个方法使用了keyPath, keyPath直译键路径, 用于确定自定义类属性中的属性;
```objc
// 使用一
[p1 setValue:@"20" forKey:@"age"];
[p1 setValue:@"30" forKeyPath:@"age"];
// 使用二
// 实例化book对象
Book *b1 = [[Book alloc] init];
b1.bookName = @"吃货大全";
p1.book = b1;
// 通过kvc修改book的名字
[p1 setValue:@"随便" forKeyPath:@"book.bookName"];
除了对NSObject 的基础使用,对于集合类,kvc也提供了一些方法;
/**
kvc 和 字典
字典里有的key值 --> p1对象中一定要由对应的属性名
字典里的key值 , 一定要和 对象中属性名保持一致
*/
NSDictionary *dict = @{@"name":@"wangwu",@"age":@"40"};
[p1 setValuesForKeysWithDictionary:dict];
- (NSDictionary<NSString *, id> *)dictionaryWithValuesForKeys:(NSArray<NSString *> *)keys;
输入一组key,返回该组key对应的Value,再转成字典返回,用于将Model转到字典。
/**
kvc 和 数组
根据keyPath 找到数组中对象的 name 属性, 并返回(数组)
NSArray *nameArray = [array valueForKeyPath:@"name"];
*/
Person *p2 = [[Person alloc] init];
p2.name = @"yellow Mokey";
Person *p3 = [[Person alloc] init];
p3.name = @"red dog";
Person *p4 = [[Person alloc] init];
p4.name = @"green chicken";
NSArray *array = @[p2,p3,p4];
// 把三个对象中的name 取出来
NSArray *nameArray = [array valueForKeyPath:@"name"];
NSLog(@"%@",nameArray);
// 输出p2,p3,p4 的name组成的(NSString*) 数组;
- 异常处理
上面的代码都是正常情况下的使用方法, 在编码过程中异常处理是比不可少的, 因此ios还未kvc编程提供了一些常用的异常处理的方法:
+ (BOOL)accessInstanceVariablesDirectly;
一个属性用于表示在查找key的过程中如果没有找到key值,是否按照_key, _iskey, key, iskey的顺序搜索成员;
- (BOOL)validateValue:(inout id __nullable * __nonnull)ioValue forKey:(NSString *)inKey error:(out NSError **)outError;
KVC提供属性值确认的API,它可以用来检查set的值是否正确、为不正确的值做一个替换值或者拒绝设置新值并返回错误原因。
- (nullable id)valueForUndefinedKey:(NSString *)key;
取值时, 当查询的key不存在时调用该方法返回值, 默认会抛出异常;
- (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key;
赋值时如果key值没找到调用该方法,默认抛出异常;
- (void)setNilValueForKey:(NSString *)key;
当给key赋值nil时调用, 默认抛出异常;
- 其他边边角角
验证 某个key对应的value是否合法- (BOOL)validateValue:(inout id __nullable * __nonnull)ioValue forKey:(NSString *)inKey error:(out NSError **)outError;
这个方法默认实现是去探测类中是否存在-(BOOL)validate<Key>:error:
的方法, 如果存储在则调用,否则直接返回YES;
@implementation Address
// country的验证方法
-(BOOL)validateCountry:(id *)value error:(out NSError * _Nullable __autoreleasing *)outError{ //在implementation里面加这个方法,它会验证是否设了非法的value
NSString* country = *value;
country = country.capitalizedString;
if ([country isEqualToString:@"Japan"]) {
return NO; //如果国家是日本,就返回NO,这里省略了错误提示,
}
return YES;
}
@end
NSError* error;
id value = @"japan";
NSString* key = @"country";// 默认会去调用validateCountry:方法
BOOL result = [add validateValue:&value forKey:key error:&error]; //如果没有重写-(BOOL)-validate<Key>:error:,默认返回Yes
if (result) {
NSLog(@"键值匹配");
[add setValue:value forKey:key];
}
else{
NSLog(@"键值不匹配"); //不能设为日本,基他国家都行
}
NSString* country = [add valueForKey:@"country"];
NSLog(@"country:%@",country);
//打印结果
2016-04-20 14:55:12.055 KVCDemo[867:58871] 键值不匹配
2016-04-20 14:55:12.056 KVCDemo[867:58871] country:China
参考
属性遍历
enumerateObjectsUsingBlock:
方法是 NSArray
的方法, 用于遍历数组中每个元素;
block
中可以通过设置stop
值确定是否继续遍历; 类似于for
循环中break
功能;
监听控件
开发中难免会与用户交互, 这就需要监听用户对于一个空间的交互, 开发中常见的实现交互的方式有:
- 拖线
在storyboard 或者xib文件中对一个button控件脱线到代码文件的@implementation
部分, 会自动创建一个方法来处理点击事件; 此时对应button控件的连接视图connection inspector
Sent Event -> Touch Up Inside 会有一个指向代码的连接;
20170506149400129896936.png
点击叉号可以删除该连接;
- 代码指定
通过控件对象的addTarget:action:forControlEvents:
方法来实现对控件的监听;
[button addTarget:self
action:@selector(didClickOptionButton:)
forControlEvents:UIControlEventTouchUpInside];
如上代码中为button设置了一个@selector
方法, 该方法存在于self
中, 处理控件的UIControlEventTouchUpInside
事件;
- 手势监听;
- 方法重写;
调用某个对象的消息方法
从开始学洗objc就知道,这门开发语言是消息驱动的,通过消息的发送和接受执行消息的传递; 除了常规的方法调用,我们还可以通过NSInvocation
和performSelector系列方法
来调用一个对象的方法;
-
performSelector
系列方法
`performSelector` 系列方法的声明在NSObject class和NSObject portocol 中均有; 通过`performSelector` 系列方法,可以设置方法执行的方式, 参数, 时间,所在线程等;
除了可以指定方法的执行方式以外, `performSelector` 与直接调用的区别还有编译器不会检查方法是否存在, 因此一个健壮的方式是使用`- (BOOL)respondsToSelector:(SEL)aSelector;` 方法判断类对象中是否有这个方法, 然后在发送执行消息; 值得一提的是`respondsToSelector:`的方法声明存在两个地方`Class NSProxy` 和`Protocol NSObject`中.
`Protocol NSObject` 中的方法
方法 | 描述 |
---|---|
performSelector: | 发送一个执行的消息 |
performSelector:withObject: | 带一个参数 |
performSelector:withObject:withObject: | 带两个参数 |
`Class NSObject` 中的方法
方法 | 描述 |
---|---|
performSelector:withObject:afterDelay: | 发送一个执行的消息,并且带参数,指定延迟时间 |
performSelector:withObject:afterDelay:inModes: | 指定执行模式 |
performSelectorOnMainThread:withObject:waitUntilDone: | waitUntilDone, 是否阻塞当前线程; |
performSelectorOnMainThread:withObject:waitUntilDone:modes: | -- |
performSelector:onThread:withObject:waitUntilDone: | -- |
performSelector:onThread:withObject:waitUntilDone:modes: | -- |
performSelectorInBackground:withObject: | -- |
例子: mode 的使用
//mode 的使用
NSArray *arr = [NSArray arrayWithObject:NSDefaultRunLoopMode];
[self performSelector:@selector(sel:)
withObject:@"active"
afterDelay:3
inModes:arr];
-
NSInvocation
使用
performSelector
可以完成大部分的消息传递操作, 但是如果参数超出2个限制,就不那么友好了. 解决办法是可以使用NSInvocation
类;-
NSInvocation
的初始化和调用
在官方文档中有明确说明,NSInvocation对象只能使用其类方法来初始化,不可使用alloc/init方法。它执行调用之前,需要设置两个方法:setSelector: 和setArgument:atIndex:
同时文档中也说明NSInvocation
是灵活的, 在invoke
一个对象之前,其签名, target和selector都是可以修改的;
-
- (void)viewDidLoad {
[super viewDidLoad];
SEL myMethod = @selector(myLog);
//创建一个函数签名,这个签名可以是任意的,但需要注意,签名函数的参数数量要和调用的一致。
NSMethodSignature * sig = [NSNumber instanceMethodSignatureForSelector:@selector(init)];
//通过签名初始化
NSInvocation * invocatin = [NSInvocation invocationWithMethodSignature:sig];
//设置target
[invocatin setTarget:self];
//设置selecteor
[invocatin setSelector:myMethod];
//消息调用
[invocatin invoke];
}
-(void)myLog{
NSLog(@"MyLog");
}
- NSInvocation的返回值
//方法一:
id res = nil;
if (signature.methodReturnLength != 0) {//有返回值
//将返回值赋值给res
[invocation getReturnValue:&res];
}
return res;
//方法二:
//可以通过signature.methodReturnType获得返回的类型编码,因此可以推断返回值的具体类型
参考
对话框
常见控件及其属性
UIScrollView
contentSize
ScrollView的内容大小, 默认是CGSizeZero. 在设置的时候, contentSize需要比scrollView 的size 要大,否则没有滚动效果;
showsHorizontalScrollIndicator
和showsVerticalScrollIndicator
, 两个BOOL 类型的值, 用于控制显示和吟唱横向/纵向指示器;
bounces
, BOOL 类型值, 用于控制弹簧效果;
alwaysBounceHorizontal
和alwaysBounceVertical
两个BOOL类型值, 用于在bounces == YES的时候,控制contentSize小于ScrollView显示区域时( 不需要滚动)是否显示 横向/纵向的弹簧效果;
contentInset
一个UIEdgeInsets
对象, 用于控制子View的内边距, 相当于增大了contentSize
;
contentOffset
, 一个CGPoint对象, 相对于子View的滚动(忽略contentInset
);
minimumZoomScale
和maximumZoomScale
属性, 用于控制最小和最大缩放倍数;
ScrollView
不能滚动的原因:
-
contentSize
比scrollView
的size 小 _scrollView.userInteractionEnabled = NO;
_scrollView.scrollEnabled = NO;
delegate
属性, 一个准守了UIScrollViewDelegate
协议的对象, 用于监听ScrollView的滑动;
在几乎所有的计算机和编程的教程中, 总是能看到各种设计模式, 但是仔细想想这些设计模式有那么重要吗? 这些看起来 "高大上" 术语是在帮助我们理解还是故意制造出来的行业壁垒? 我只能自己尽量避免使用我认为不必要的术语.
UIScrollViewDelegate
, ScrollView的代理协议, 包括如下一些方法: 这些方法都是@optional
的
- (void)scrollViewDidScroll:(UIScrollView *)scrollView;
- (void)scrollViewDidZoom:(UIScrollView *)scrollView;
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView;
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset;
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate;
- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView;
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView;
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView;
- (nullable UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView;
- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(nullable UIView *)view;
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(nullable UIView *)view atScale:(CGFloat)scale;
- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView;
- (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView;
pagingEnabled
BOOL 类型属性, 是否显示分页效果;分页效果以scrollView
的宽度为基准,与子view的内容没有关系;分页效果忽略contentInset
属性设置的边距;
一个测试用代码:
CGSize scrollViewSize = _scrollView.frame.size;
for (int i = 0; i < kImageCount; i++) {
// 计算imageView的x值
// ****** imageView的x值 +5,将每张图片向后平移5个点;
// ****** 测试结果:分页效果是不根据子View(图片)来分页,而是根据ScrollView的宽度;
CGFloat imageViewX = i * (scrollViewSize.width +5);
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(imageViewX, 0, scrollViewSize.width, scrollViewSize.height)];
// 设置图片
// imageView.image =[UIImage imageNamed:@"img_01"];
// 拼接图片的名称
NSString *imageName = [NSString stringWithFormat:@"img_%02d",i + 1];
imageView.image = [UIImage imageNamed:imageName];
// 添加到scrollView
[_scrollView addSubview:imageView];
}
// 设置 scrollView的contentSize
_scrollView.contentSize = CGSizeMake(kImageCount * scrollViewSize.width, 0);
// ****** 设置边距 ,测试结果表明分页会忽略边距;
_scrollView.contentInset = UIEdgeInsetsMake(10, 50, 10, 50);
// scrollView的分页效果 (根据scrollView的宽度进行分页的)
_scrollView.pagingEnabled = YES;
ScrollView的滚动, 可以通过setContentOffset:animated:
方法来实现;
// offset: 最终要显示的位置
// animated: 是否显示滚动过程
[_scrollView setContentOffset:offset animated:YES];
UIPageControl
UIPageControl
显示一个横向的点, 用于指示作用, 可以与ScrollView配合使用;
属性 | 作用 |
---|---|
numberOfPages |
一共需要显示多少点 |
currentPage |
当前的点, 可以通过该属性直接设置当前选中点的 |
pageIndicatorTintColor |
非选中点的颜色 |
currentPageIndicatorTintColor |
选中点的颜色 |
点击事件相关
UIPageControl
继承至UIControl
, 因此可以添加一个点击事件监听;经测试监听的时间为UIControlEventValueChanged
;
[_pageControl addTarget:self action:@selector(pgct:) forControlEvents:UIControlEventValueChanged];
控件点击后会根据点击位置与当前位置的差值确定对currentPage
的加减;
重要
defersCurrentPageDisplay
,一个BOOL值, 用于延迟currentPage对空间的显示, 当设置为YES的时候, 点击空间currentPage值依旧会变化,但是不会反应到界面上;需要显示调用[_pageControl updateCurrentPageDisplay];
方法;
- (IBAction)pgct:(id)sender {
// 当defersCurrentPageDisplay == YES的时候, currentPage依旧增减, 但是界面不会变化;
NSLog(@"__%s__, %ld", __func__, _pageControl.currentPage);
// 显示调用如下方法,更新界面;
[_pageControl updateCurrentPageDisplay];
}
defersCurrentPageDisplay
不适用于直接设置currentPage的值, 直接设置依旧会更新界面;
NSTimer
NSTimer
继承至NSObject
, 用于设置一个定时器,可以设置重复执行,预约执行,触发和取消执行;
可以通过如下三种方式构建一个NSTimer
对象:
-
+ scheduledTimerWithTimeInterval
系列方法, 初始化一个NSTimer 对象,并将该对象放入当前loop中; -
+ timerWithTimeInterval
系列方法, 仅创建一个对象; -
- initWithFireDate:interval:target:selector:userInfo:repeats:
方法, 初始化一个alloc
的方法;
方法 | 描述 |
---|---|
+ scheduledTimerWithTimeInterval:invocation:repeats: | 根据invocation 指定具体的执行任务 |
+ scheduledTimerWithTimeInterval:target:selector:userInfo:repeats: | 根据target和selector指定具体执行任务 |
+ timerWithTimeInterval:invocation:repeats: | 同上, 不放入默认run loop |
+ timerWithTimeInterval:target:selector:userInfo:repeats: | --- |
- initWithFireDate:interval:target:selector:userInfo:repeats: | alloc init实现初始化 |
+ timerWithTimeInterval:repeats:block: | --- |
+ scheduledTimerWithTimeInterval:repeats:block: | --- |
- fire | 触发任务执行 |
- invalidate | 从任务队列中移除 |
属性 | 描述 |
---|---|
valid | 一个BOOL值, 用来判断当前timer是否有效 |
fireDate | 触发时间 |
timeInterval | 触发间隔 |
userInfo | 构建对象时传入的数据 |
NSRunLoop
NSRunLoop
用于处理出入请求, 系统提醒 NSPort
对象, NSConnection
对象 和 NSTimer
事件; 我们可以理解NSRunLoop
是一个无线循环, 会不停的循环执行并检查自己的输入源中是否有待执行的事件;
NSRunLoop
不能被应用主动创建或管理, 可以通过NSRunLoop
的类方法获取当前线程的loop对象[NSRunLoop currentRunLoop];
, 和主线程loop对象[NSRunLoop mainRunLoop];
NSRunLoop
的运行模式, loop内部有不同的运行模式, 不同的输入源运行在不同的模式上!
未完待续...
参考
未完待续...
网友评论