大图片在渲染的时候,比较耗费时间
我们利用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 文件
#import
typedef 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]; // 添加监听者
}