YYKit真是一個(gè)非常優(yōu)秀的框架!
最近看YYLabel源碼港粱,看到其中一段代碼非常有意思隔盛,作者在要display layer的守候獲取一個(gè)串行隊(duì)列,把繪制任務(wù)放入其中完成異步繪制沮翔。好的代碼自己也臨摹了一下陨帆,以做紀(jì)念。
1采蚀、創(chuàng)建兩個(gè)內(nèi)聯(lián)函數(shù)用于返回不同優(yōu)先級(jí)的狀態(tài)以及一個(gè)結(jié)構(gòu)體用于存儲(chǔ)不同優(yōu)先級(jí)下的隊(duì)列池疲牵,以及相關(guān)信息
//也就是說(shuō)建議編譯器將指定的函數(shù)體插入并取代每一處調(diào)用該函數(shù)的地方(上下文),從而節(jié)省了每次調(diào)用函數(shù)帶來(lái)的額外時(shí)間開支
static inline dispatch_queue_priority_t NSQualityOfServiceToDispatchPriority(NSQualityOfService qos){//<ios8
switch (qos) {
case NSQualityOfServiceUserInteractive:
return DISPATCH_QUEUE_PRIORITY_HIGH;
case NSQualityOfServiceUserInitiated:
return DISPATCH_QUEUE_PRIORITY_HIGH;
case NSQualityOfServiceUtility:
return DISPATCH_QUEUE_PRIORITY_LOW;
case NSQualityOfServiceBackground:
return DISPATCH_QUEUE_PRIORITY_BACKGROUND;
case NSQualityOfServiceDefault:
return DISPATCH_QUEUE_PRIORITY_DEFAULT;
default:
return DISPATCH_QUEUE_PRIORITY_DEFAULT;
}
}
static inline dispatch_qos_class_t NSQualityOfServiceToQOSClass(NSQualityOfService qos){//>ios8 其目的相同都是為了設(shè)置給隊(duì)列設(shè)置不同的優(yōu)先級(jí)榆鼠。
switch (qos) {
case NSQualityOfServiceUserInteractive:
return QOS_CLASS_USER_INTERACTIVE;
case NSQualityOfServiceUserInitiated:
return QOS_CLASS_USER_INITIATED;
case NSQualityOfServiceUtility:
return QOS_CLASS_UTILITY;
case NSQualityOfServiceBackground:
return QOS_CLASS_BACKGROUND;
case NSQualityOfServiceDefault:
return QOS_CLASS_DEFAULT;
default:
return QOS_CLASS_DEFAULT;
}
}
typedef struct {
int countCount;//隊(duì)列數(shù)量
atomic_int counter;//原子計(jì)數(shù)器纲爸,用來(lái)記錄是第幾次取隊(duì)列
void* *queues;//隊(duì)列數(shù)組
char* name;//context name
}LHDispatchContext;
2、取隊(duì)列方法 其中我把原子計(jì)數(shù)方法替換成了 atomic_fetch_add_explicit妆够,蘋果iOS10后用此方法代替OSAtomicIncrement32
static dispatch_queue_t LHDispatchQueueGetFromContex(LHDispatchContext*contex){
atomic_fetch_add_explicit(&contex->counter,1,memory_order_relaxed);//原子累加計(jì)數(shù)识啦,用于記錄此方法被訪問(wèn)次數(shù)
int a =contex->counter%contex->countCount;//取余负蚊,為的是按順序取隊(duì)列,因?yàn)殛?duì)列是串行颓哮,這樣做的話提高效率家妆。
return(__bridge dispatch_queue_t) contex->queues[a];
}
3、隊(duì)列創(chuàng)建方法的實(shí)現(xiàn)冕茅。NSQualityOfServiceToQOSClass伤极、NSQualityOfServiceToDispatchPriority 兩個(gè)函數(shù) 作者是用內(nèi)聯(lián)函數(shù)實(shí)現(xiàn)。提高效率姨伤。用于返回優(yōu)先級(jí)哨坪。
static LHDispatchContext* LHDispatchCreatQueue(char*name,int quneCount,NSQualityOfService qos){
LHDispatchContext*contex =calloc(1, sizeof(LHDispatchContext));
contex->countCount=quneCount;
contex->name =name;
if (!contex) {
return NULL;
}
contex->queues=calloc(quneCount, sizeof(void*));
if (!contex->queues) {
free(contex);
}
if ([UIDevice currentDevice].systemVersion.floatValue>8.0) {
dispatch_qos_class_t qos_class = NSQualityOfServiceToQOSClass(qos);
dispatch_queue_attr_t att = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, qos_class, 0);
for (int i=0; i<quneCount; i++) {
dispatch_queue_t q = dispatch_queue_create(name, att);
contex->queues[i]=(__bridge_retained void*)q;
}
}else{
for (int i=0; i<quneCount; i++) {
long identifier = NSQualityOfServiceToDispatchPriority(qos);
dispatch_queue_t q = dispatch_queue_create(name, DISPATCH_QUEUE_SERIAL);
dispatch_set_target_queue(q, dispatch_get_global_queue(identifier, 0));
contex->queues[i] =(__bridge_retained void*)q;
}
}
return contex;
}
4、根據(jù)不同的優(yōu)先級(jí)創(chuàng)建隊(duì)列組乍楚。其中用到了單例模式当编,實(shí)現(xiàn)全局的獲取,避免多次創(chuàng)建徒溪。
static LHDispatchContext* LHDispatchGetContexforQos(NSQualityOfService qos){
static LHDispatchContext* contexArr[5]={0};//創(chuàng)建一個(gè)LHDispatchContext數(shù)組用與存儲(chǔ)不同優(yōu)先級(jí)下的contex忿偷。
switch (qos) {
case NSQualityOfServiceUserInteractive:{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
int count = (int)[NSProcessInfo processInfo].activeProcessorCount;
count = count<1?1:count>MaxQueueCount?MaxQueueCount:count;
contexArr[0] = LHDispatchCreatQueue("com.lh.pool-user-Interactive", count, qos);
});
return contexArr[0];
}break;
case NSQualityOfServiceUserInitiated: {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
int count = (int)[NSProcessInfo processInfo].activeProcessorCount;
count = count<1?1:count>MaxQueueCount?MaxQueueCount:count;//取當(dāng)前活躍的進(jìn)程數(shù),創(chuàng)建串行隊(duì)列數(shù)組词渤,以達(dá)到資源的合理利用牵舱。
contexArr[1] = LHDispatchCreatQueue("com.lh.pool-user-Initiated", count, qos);
});
return contexArr[1];
break;
}
case NSQualityOfServiceUtility: {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
int count = (int)[NSProcessInfo processInfo].activeProcessorCount;
count = count<1?1:count>MaxQueueCount?MaxQueueCount:count;
contexArr[2] = LHDispatchCreatQueue("com.lh.pool-user-Utility", count, qos);
});
return contexArr[2];
break;
}
case NSQualityOfServiceBackground: {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
int count = (int)[NSProcessInfo processInfo].activeProcessorCount;
count = count<1?1:count>MaxQueueCount?MaxQueueCount:count;
contexArr[3] = LHDispatchCreatQueue("com.lh.pool-user-Background", count, qos);
});
return contexArr[3];
break;
}
case NSQualityOfServiceDefault: {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
int count = (int)[NSProcessInfo processInfo].activeProcessorCount;
count = count<1?1:count>MaxQueueCount?MaxQueueCount:count;
contexArr[4] = LHDispatchCreatQueue("com.lh.pool-user-Default", count, qos);
});
return contexArr[4];
break;
}
}
return NULL;
}
最后總結(jié):
- YYLabel 可以用來(lái)實(shí)現(xiàn)異步渲染。
- 當(dāng)改變了 Frame缺虐、更新了 UIView/CALayer 的層次時(shí)芜壁,或者手動(dòng)調(diào)用了 UIView/CALayer 的 setNeedsLayout/setNeedsDisplay方法后,這個(gè) UIView/CALayer 就被標(biāo)記為待處理高氮,并被提交到一個(gè)全局的容器去
- 由于runloop會(huì)在即將進(jìn)入休眠或者退出時(shí)處理所有被標(biāo)記過(guò)的UIView/CALayer慧妄,通過(guò)調(diào)用drawrect/display完成渲染。
- N個(gè)串行隊(duì)列相當(dāng)于N個(gè)一條生產(chǎn)線的渲染工廠剪芍,我按順序把任務(wù)分配給各個(gè)工廠塞淹,非常井井有條的一種生產(chǎn)分配方式??。