- (void)viewDidLoad { [super viewDidLoad]; CFRunLoopRef ref = CFRunLoopGetMain(); CFArrayRef arr = CFRunLoopCopyAllModes(ref); for (CFIndex i = 0; i < CFArrayGetCount(arr); i ++) { NSString *str = (__bridge NSString *)CFArrayGetValueAtIndex(arr, i); NSLog(@"AllMode:%@", str); } NSString *currentMode = (__bridge NSString *)CFRunLoopCopyCurrentMode(ref); NSLog(@"currentMode:%@", currentMode);}复制代码
运行结果如下:
从运行结果来看,MainLoop所有模式有4种,但当前模式只有一种。
struct __CFRunLoop { ... ... pthread_t _pthread; CFRunLoopModeRef _currentMode; CFMutableSetRef _modes; ... ...}复制代码
上面是__CFRunLoop的数据结构,可以看出_modes是Set类型,_currentMode只有一种。另外我们也可以看出__CFRunLoop是绑定了一个pthread_t的。
接下来我们来看一下__CFRunLoopMode。
struct __CFRunLoopMode { ... ... CFMutableSetRef _sources0; CFMutableSetRef _sources1; CFMutableArrayRef _observers; CFMutableArrayRef _timers; ... ...}复制代码
从_CFRunLoopMode的数据结构我们可以看出,mode包含三种类型的事件:source、observer、timer。
CFRunLoopTimer
接下来,我们来尝试实现一个timer。
- (void)viewDidLoad { [super viewDidLoad]; CFRunLoopRef ref = CFRunLoopGetMain(); CFOptionFlags flag = kCFRunLoopBeforeTimers; __block CFIndex i = 0; CFRunLoopTimerRef timerRef = CFRunLoopTimerCreateWithHandler(CFAllocatorGetDefault(), CFAbsoluteTimeGetCurrent(), 0.1, flag, 0, ^(CFRunLoopTimerRef timer) { i++; NSLog(@"Test%ld: %f", i, CFRunLoopGetNextTimerFireDate(ref, kCFRunLoopDefaultMode)); if (i == 10) { CFRunLoopTimerInvalidate(timer); CFRunLoopRemoveTimer(ref, timer, kCFRunLoopDefaultMode); } }); CFRunLoopAddTimer(ref, timerRef, kCFRunLoopDefaultMode);}复制代码
运行结果如下:
CFRunLoopObserver
- (void)viewDidLoad { [super viewDidLoad]; CFRunLoopRef ref = CFRunLoopGetMain(); CFRunLoopObserverRef observerRef = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) { if (activity == kCFRunLoopEntry) { NSLog(@"Entry"); } if (activity == kCFRunLoopBeforeTimers) { NSLog(@"Timers"); } if (activity == kCFRunLoopBeforeSources) { NSLog(@"Source"); } if (activity == kCFRunLoopBeforeWaiting) { NSLog(@"BeforeWaiting"); } if (activity == kCFRunLoopAfterWaiting) { NSLog(@"AfterWaiting"); } if (activity == kCFRunLoopRunStopped) { NSLog(@"Stopped"); } }); CFRunLoopAddObserver(ref, observerRef, kCFRunLoopDefaultMode);}复制代码
当应用处于等待时:
从运行结果上看,程序在停止等待后,会先创建timer,timer创建后发现无事可做,立刻被销毁,紧接着创建了source事件,然后开始等待接受事件。如此循环,而stopped却始终不会执行。如此便可保证程序一直在运行。UITableView刷新优化
#import "ViewController.h"typedef void(^askMessageBlock)(void);typedef void(^reloadTableViewBlock)(void);@interface ViewController ()@property (nonatomic, strong) UITableView *tableView;@property (nonatomic, copy) askMessageBlock askblock;@property (nonatomic, copy) reloadTableViewBlock reloadBlock;@end@implementation ViewController- (void)viewDidLoad { [super viewDidLoad]; CFRunLoopRef ref = CFRunLoopGetMain(); _tableView = [[UITableView alloc] initWithFrame:self.view.frame style:UITableViewStyleGrouped]; _tableView.dataSource = self; _tableView.delegate = self; [_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"TableCell"]; [self.view addSubview:_tableView]; CFRunLoopObserverRef observerRef = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) { __block BOOL scrollEnd = YES; CFRunLoopPerformBlock(ref, UITrackingRunLoopMode, ^{ self.askblock = ^{ NSLog(@"Ask Message"); }; self.reloadBlock = ^{ NSLog(@"Reload TableView"); }; NSLog(@"TableView is Scrolling"); scrollEnd = NO; }); if (scrollEnd == YES) { if (activity == kCFRunLoopBeforeWaiting) { if (self.askblock) { self.askblock(); self.askblock = NULL; } } if (activity == kCFRunLoopAfterWaiting) { if (self.reloadBlock) { self.reloadBlock(); self.reloadBlock = NULL; } } } }); CFRunLoopAddObserver(ref, observerRef, kCFRunLoopDefaultMode);}#pragma mark - UITableViewDataSource- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1;}- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return 100;}- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"TableCell"]; return cell;}#pragma mark - UITableViewDelegate- (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated.}@end复制代码
提供一种思路,欢迎大神指导。
UITableView继承于UIScrollView,UIScrollView针对视图的滚动提供了相应的接口。
// 开始拖拽- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView;// 已经开始滚动- (void)scrollViewDidScroll:(UIScrollView *)scrollView;// 开始减速- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView;// 终止- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView;复制代码
CFRunLoopSource
相较于timer和observer,source事件提供了两种sourceContext:CFRunloopSourceContext、CFRunLoopSourceContext1。下面我们来看一下两者的区别:
typedef struct { ... ... void (*schedule)(void *info, CFRunLoopRef rl, CFStringRef mode); void (*cancel)(void *info, CFRunLoopRef rl, CFStringRef mode); void (*perform)(void *info);} CFRunLoopSourceContext;typedef struct { ... ... void * (*getPort)(void *info); void (*perform)(void *info);} CFRunLoopSourceContext1复制代码
这里省去了部分代码,主要看一下不同点。从两者的比较来看,CFRunLoopSourceContext1主要针对的是端口事件,CFRunLoopSourceContext针对触摸等事件。
CF_EXPORT CFRunLoopSourceRef CFRunLoopSourceCreate(CFAllocatorRef allocator, CFIndex order, CFRunLoopSourceContext *context);复制代码
CFRunLoop针对source事件只提供了一个构造方法。针对RunLoop的source事件,对应于手势事件、晃动事件、及远端事件。大家可以在上述事件的使用中去理解RunLoop的Source事件。
关于RunLoop就写到这里,以后有新的想法会及时补充与更正。