大图片在渲染的时候,比较耗费时间
我们利用RUNLOOP 来优化:
思路:1.每一次RUNLOOP,都只加载一个小任物,把图片任务放到数组,从数组循环来加载.这样可以是项目达到流畅.
2.只加载当前视图内的图片任务
3.为了不让runloop休眠.我们要用一个timer区持有这个runloop 或者 通知注册runloop事件,让快要睡眠的时候去执行唤醒.
直接贴代码
#import "DWURunLoopWorkDistribution.h" #import#define DWURunLoopWorkDistribution_DEBUG 1 @interface DWURunLoopWorkDistribution () @property (nonatomic, strong) NSMutableArray *tasks; @property (nonatomic, strong) NSMutableArray *tasksKeys; @property (nonatomic, strong) NSTimer *timer; @end @implementation DWURunLoopWorkDistribution - (void)removeAllTasks { [self.tasks removeAllObjects]; [self.tasksKeys removeAllObjects]; } - (void)addTask:(DWURunLoopWorkDistributionUnit)unit withKey:(id)key{ //将任务对应的添加到task 和 taskkeys数组数组中方便在注册方法中的callback中以待处理 [self.tasks addObject:unit]; [self.tasksKeys addObject:key]; // NSLog(@"%@%@",unit,key); if (self.tasks.count > self.maximumQueueLength) { [self.tasks removeObjectAtIndex:0]; [self.tasksKeys removeObjectAtIndex:0]; } } - (void)_timerFiredMethod:(NSTimer *)timer { //We do nothing here } - (instancetype)init { if ((self = [super init])) { _maximumQueueLength = 30; _tasks = [NSMutableArray array]; _tasksKeys = [NSMutableArray array]; // _timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(_timerFiredMethod:) userInfo:nil repeats:YES]; } return self; } + (instancetype)sharedRunLoopWorkDistribution { static DWURunLoopWorkDistribution *singleton; static dispatch_once_t once; dispatch_once(&once, ^{ singleton = [[DWURunLoopWorkDistribution alloc] init]; [self _registerRunLoopWorkDistributionAsMainRunloopObserver:singleton]; }); return singleton; } + (void)_registerRunLoopWorkDistributionAsMainRunloopObserver:(DWURunLoopWorkDistribution *)runLoopWorkDistribution { static CFRunLoopObserverRef defaultModeObserver; //kCFRunLoopBeforeWaiting RUNLOOP 进入休眠的时候唤醒 _registerObserver(kCFRunLoopBeforeWaiting, defaultModeObserver, NSIntegerMax - 999, kCFRunLoopDefaultMode, (__bridge void *)runLoopWorkDistribution, &_defaultModeRunLoopWorkDistributionCallback); /* 1. kCFRunLoopDefaultMode: 默认 mode,通常主线程在这个 Mode 下运行。 2. UITrackingRunLoopMode: 追踪mode,保证Scrollview滑动顺畅不受其他 mode 影响。 3. UIInitializationRunLoopMode: 启动程序后的过渡mode,启动完成后就不再使用。 4: GSEventReceiveRunLoopMode: Graphic相关事件的mode,通常用不到。 5: kCFRunLoopCommonModes: 占位mode,作为标记DefaultMode和CommonMode用。 */ } // 验证下 这是什么调用方法 static static void _registerObserver(CFOptionFlags activities, CFRunLoopObserverRef observer, CFIndex order, CFStringRef mode, void *info, CFRunLoopObserverCallBack callback) { CFRunLoopRef runLoop = CFRunLoopGetCurrent(); CFRunLoopObserverContext context = { 0, info, &CFRetain, &CFRelease, NULL }; // switch (activities) { // case kCFRunLoopEntry: // NSLog(@"即将进入runloop"); // break; // case kCFRunLoopBeforeTimers: // NSLog(@"即将处理timer"); // break; // case kCFRunLoopBeforeSources: // NSLog(@"即将处理input Sources"); // break; // case kCFRunLoopBeforeWaiting: // NSLog(@"即将睡眠"); // break; // case kCFRunLoopAfterWaiting: // NSLog(@"从睡眠中唤醒,处理完唤醒源之前"); // break; // case kCFRunLoopExit: // NSLog(@"退出"); // break; // } observer = CFRunLoopObserverCreate( NULL, activities, YES, order, callback, &context); CFRunLoopAddObserver(runLoop, observer, mode); //创建一个runloop观察者 /* CFAllocatorRef allocator:内存分配 CFOptionFlags activities :唤醒标志 Boolean repeats:是否重复 CFIndex order :优先级 CFRunLoopObserverCallBack callout :回调 绑定 CFRunLoopObserverContext *context :传递 */ CFRelease(observer); } //typedef void (*CFRunLoopObserverCallBack)(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info); static void _runLoopWorkDistributionCallback(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info) { // __bridge 类型 实现id类型与void*类型 DWURunLoopWorkDistribution *runLoopWorkDistribution = (__bridge DWURunLoopWorkDistribution *)info; if (runLoopWorkDistribution.tasks.count == 0) { return; } BOOL result = NO; while (result == NO && runLoopWorkDistribution.tasks.count) { DWURunLoopWorkDistributionUnit unit = runLoopWorkDistribution.tasks.firstObject; result = unit(); [runLoopWorkDistribution.tasks removeObjectAtIndex:0]; [runLoopWorkDistribution.tasksKeys removeObjectAtIndex:0]; } } static void _defaultModeRunLoopWorkDistributionCallback(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info) { NSLog(@"---------> Callback唤醒回调 当前状态CFRunLoopActivity[%lu]",activity); //CFRunLoopObserverRef 观察者 //CFRunLoopActivity RUNLOOP状态 kCFRunLoopBeforeWaiting // 接下来执行 _runLoopWorkDistributionCallback _runLoopWorkDistributionCallback(observer, activity, info); // kCFRunLoopEntry = (1UL << 0), // 即将进入Loop // kCFRunLoopBeforeTimers = (1UL << 1), // 即将处理 Timer // kCFRunLoopBeforeSources = (1UL << 2), // 即将处理 Source // kCFRunLoopBeforeWaiting = (1UL << 5), // 即将进入休眠 // kCFRunLoopAfterWaiting = (1UL << 6), // 刚从休眠中唤醒 // kCFRunLoopExit = (1UL << 7), // 即将退出Loop } @end @implementation UITableViewCell (DWURunLoopWorkDistribution) @dynamic currentIndexPath; - (NSIndexPath *)currentIndexPath { NSIndexPath *indexPath = objc_getAssociatedObject(self, @selector(currentIndexPath)); return indexPath; } - (void)setCurrentIndexPath:(NSIndexPath *)currentIndexPath { objc_setAssociatedObject(self, @selector(currentIndexPath), currentIndexPath, OBJC_ASSOCIATION_RETAIN_NONATOMIC); //这四个后面的参数分别表示:源对象,关键字,关联的对象和一个关联策略。 }
.h 文件
#importtypedef BOOL(^DWURunLoopWorkDistributionUnit)(void); @interface DWURunLoopWorkDistribution : NSObject @property (nonatomic, assign) NSUInteger maximumQueueLength; + (instancetype)sharedRunLoopWorkDistribution; - (void)addTask:(DWURunLoopWorkDistributionUnit)unit withKey:(id)key; - (void)removeAllTasks; @end @interface UITableViewCell (DWURunLoopWorkDistribution) @property (nonatomic, strong) NSIndexPath *currentIndexPath; @end
代码分析来源于:
推荐一个第三方RunLoopWorkDistribution,地址https://github.com/diwu/RunLoopWorkDistribution
我们可以添加观察者 监听RUNLOOP的循环
// 添加一个监听者
- (void)addObserver { // 1. 创建监听者 /** * 创建监听者 * * @param allocator#> 分配存储空间 * @param activities#> 要监听的状态 * @param repeats#> 是否持续监听 * @param order#> 优先级, 默认为0 * @param observer 观察者 * @param activity 监听回调的当前状态 */ CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) { /* kCFRunLoopEntry = (1UL << 0), 进入工作 kCFRunLoopBeforeTimers = (1UL << 1), 即将处理Timers事件 kCFRunLoopBeforeSources = (1UL << 2), 即将处理Source事件 kCFRunLoopBeforeWaiting = (1UL << 5), 即将休眠 kCFRunLoopAfterWaiting = (1UL << 6), 被唤醒 kCFRunLoopExit = (1UL << 7), 退出RunLoop kCFRunLoopAllActivities = 0x0FFFFFFFU 监听所有事件 */ //NSLog(@"%@", [NSRunLoop currentRunLoop].currentMode); // 查看当前的RunLoop运行状态 switch (activity) { case kCFRunLoopEntry: NSLog(@"RunLoop--进入"); break; case kCFRunLoopBeforeTimers: NSLog(@"RunLoop--Timer事件"); break; case kCFRunLoopBeforeSources: NSLog(@"RunLoop--Source事件"); break; case kCFRunLoopBeforeWaiting: NSLog(@"RunLoop--休眠"); break; case kCFRunLoopAfterWaiting: NSLog(@"RunLoop--唤醒"); break; case kCFRunLoopExit: NSLog(@"RunLoop--退出"); break; default: break; } }); // 2. 添加监听者 /** * 给指定的RunLoop添加监听者 * * @param rl#> 要添加监听者的RunLoop * @param observer#> 监听者对象 * @param mode#> RunLoop的运行模式, 填写默认模式即可 */ CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode); }
- (void)viewDidLoad { [super viewDidLoad]; [self addObserver]; // 添加监听者 }
看log
正常的RUNLOOP 是 睡眠 唤醒 一个循环结束
我们他RUNLOOP不休眠 一直在即将睡眠的时候唤醒