RunLoop源代码学习(二)对象管理

2021-08-12

前言

上篇 RunLoop源代码学习(一)基本数据结构 简单过了一下 RunLoop 的相关数据结构,本篇介绍 RunLoop 的对象管理。RunLoop 的主要管理对象包括 Modes、监控对象(Sources、Observers、Timers)以及比较特殊的 Common Modes。

一、Modes管理

RunLoop 对 Modes 的管理逻辑比较简单,CFRunLoop没有公开显式的添加 Mode 的接口,也没有提供移除 Mode 的接口。

添加 Mode 是在__CFRunLoopFindMode方法中实现的,上篇有介绍过,Find Mode 会在CFRunLoop_modes成员(CFMutableSetRef类型,元素是CFRunLoopModeRef类型)按名称查找目标 Mode,如果查找不到,则创建一个新的 Mode。

RunLoop 内部也没有用于移除的 Mode 的方法,因为需要移除 Mode 的时候,RunLoop 也该析构了,也就是说 Mode 的移除,其实是在 RunLoop 析构中实现的。总之就是,RunLoop 要么不移除任何 Mode,需要移除的时候则移除所有 Modes。

二、监控对象管理

监控对象管理逻辑中其实穿插了很多 CommonModes 管理的代码,本章节中遇到这些代码会做字体加粗处理。在第三章学习 CommonModes 管理时进行汇总。

2.1 Sources

添加目标 Source 到指定的 Mode 的操作如下:

  • 目标 Mode 为 CommonModes
    • 将目标 Source 添加到 commonModeItems 集合中
    • 将目标 Source 添加到 CommonModes 所包含的所有 Modes 中
  • 目标 Mode 不是 CommonModes:
    • 如果目标 Source 是 Source0:将目标 Source 添加到 Mode 的_sources0集合中,如果目标 Source 的context.version0.schedule有值,则标记为“添加成功时需要触发操作”;
    • 如果目标 Source 是 Source1:将目标 Source 添加到 Mode 的_sources1集合中,并更新 Mode 的_portToV1SourceMap字典;
    • 更新目标 Source 的_runLoops集合(对所有添加了该 Source 的 RunLoop 的反向引用);
  • 如果 Source 是 Source0 且标记为“添加成功时需要触发操作”:则触发context.version0.schedule

NOTE:_modes的数据类型是CFMutableSetRef,元素是CFRunLoopModeRef_commonModes的数据类型是CFMutableSetRef,元素是CFStringRef

NOTE:CFSetApplyFunction(set, (__CFRunLoopAddItemToCommonModes), (void *)context)的作用是:遍历set的所有元素,以元素以及context为传参,调用__CFRunLoopAddItemToCommonModes函数。

// 省略掉一些简单的懒加载代码
void CFRunLoopAddSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStringRef modeName) {	/* DOES CALLOUT */
    CHECK_FOR_FORK();
    if (__CFRunLoopIsDeallocating(rl)) return;
    if (!__CFIsValid(rls)) return;
    Boolean doVer0Callout = false;
    __CFRunLoopLock(rl);
    if (modeName == kCFRunLoopCommonModes) {
	CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
        
        ...
        
        //核心操作1:将目标Source添加到_commonModeItems集合中
	CFSetAddValue(rl->_commonModeItems, rls);
	if (NULL != set) {
	    CFTypeRef context[2] = {rl, rls};
            //核心操作2:将目标Source添加到CommonModes所包含的所有Modes中
	    CFSetApplyFunction(set, (__CFRunLoopAddItemToCommonModes), (void *)context);
	    CFRelease(set);
	}
    } else {
	CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, true);
        
        ...
        
	if (NULL != rlm && !CFSetContainsValue(rlm->_sources0, rls) && !CFSetContainsValue(rlm->_sources1, rls)) {
            // 核心操作3:将目标Source添加到_source0或_source1中
	    if (0 == rls->_context.version0.version) {
	        CFSetAddValue(rlm->_sources0, rls);
	    } else if (1 == rls->_context.version0.version) {
	        CFSetAddValue(rlm->_sources1, rls);
		__CFPort src_port = rls->_context.version1.getPort(rls->_context.version1.info);
		if (CFPORT_NULL != src_port) {
		    CFDictionarySetValue(rlm->_portToV1SourceMap, (const void *)(uintptr_t)src_port, rls);
		    __CFPortSetInsert(src_port, rlm->_portSet);
	        }
	    }
	    __CFRunLoopSourceLock(rls);
            
            ...
            
            // 核心操作4:更新目标Source对“添加了该Source的所有RunLoop”的反向引用集合
	    CFBagAddValue(rls->_runLoops, rl);
	    __CFRunLoopSourceUnlock(rls);
	    if (0 == rls->_context.version0.version) {
	        if (NULL != rls->_context.version0.schedule) {
                    // 核心操作5:标记为“添加成功时需要触发操作”
	            doVer0Callout = true;
	        }
	    }
	}
        if (NULL != rlm) {
	    __CFRunLoopModeUnlock(rlm);
	}
    }
    __CFRunLoopUnlock(rl);
    // 核心操作6:如果标记为“添加成功时需要触发操作”,则触发_context.version0.schedule
    if (doVer0Callout) {
	rls->_context.version0.schedule(rls->_context.version0.info, rl, modeName);	/* CALLOUT */
    }
}
复制代码

将目标 Source 从指定 Mode 中移除的操作如下:

  • 目标 Mode 为 CommonModes
    • 将目标 Source 从 commonModeItems 集合中移除
    • 将目标 Source 从 CommonModes 所包含的所有 Modes 中移除
  • 目标 Mode 不是 CommonModes:
    • 如果目标 Source 是 Source0:将目标 Source 从 Mode 的_sources0集合中移除,如果目标 Source 的context.version0.cancel有值,则标记为“移除成功时需要触发操作”;
    • 如果目标 Source 是 Source1:将目标 Source 从 Mode 的_sources1集合中移除,并更新 Mode 的_portToV1SourceMap字典;
    • 更新目标 Source 的_runLoops集合;
  • 如果 Source 是 Source0 且标记为“移除成功时需要触发操作”:则触发context.version0.cancel

NOTE:不难发现,CFRunLoopRemoveSourceCFRunLoopAddSource的逻辑其实是高度对称的。

void CFRunLoopRemoveSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStringRef modeName) {	/* DOES CALLOUT */
    CHECK_FOR_FORK();
    Boolean doVer0Callout = false, doRLSRelease = false;
    __CFRunLoopLock(rl);
    if (modeName == kCFRunLoopCommonModes) {
	if (NULL != rl->_commonModeItems && CFSetContainsValue(rl->_commonModeItems, rls)) {
	    CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
            //核心操作1:移除commonModeItems中的该Source
	    CFSetRemoveValue(rl->_commonModeItems, rls);
	    if (NULL != set) {
		CFTypeRef context[2] = {rl, rls};
                //核心操作2:遍历所有commonModes的Modes,移除目标Source
		CFSetApplyFunction(set, (__CFRunLoopRemoveItemFromCommonModes), (void *)context);
		CFRelease(set);
	    }
	}
    } else {
	CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, false);
	if (NULL != rlm && ((NULL != rlm->_sources0 && CFSetContainsValue(rlm->_sources0, rls)) || (NULL != rlm->_sources1 && CFSetContainsValue(rlm->_sources1, rls)))) {
	    CFRetain(rls);
	    if (1 == rls->_context.version0.version) {
		__CFPort src_port = rls->_context.version1.getPort(rls->_context.version1.info);
                if (CFPORT_NULL != src_port) {
		    CFDictionaryRemoveValue(rlm->_portToV1SourceMap, (const void *)(uintptr_t)src_port);
                    __CFPortSetRemove(src_port, rlm->_portSet);
                }
	    }
            // 核心操作3:将目标Source从_source0或_source1中移除
	    CFSetRemoveValue(rlm->_sources0, rls);
	    CFSetRemoveValue(rlm->_sources1, rls);
            __CFRunLoopSourceLock(rls);
            // 核心操作4:更新目标Source对“添加了该Source的所有RunLoop”的反向引用集合
            if (NULL != rls->_runLoops) {
                CFBagRemoveValue(rls->_runLoops, rl);
            }
            __CFRunLoopSourceUnlock(rls);
	    if (0 == rls->_context.version0.version) {
	        if (NULL != rls->_context.version0.cancel) {
                    // 核心操作5:标记为“移除成功时需要触发操作”
	            doVer0Callout = true;
	        }
	    }
	    doRLSRelease = true;
	}
        if (NULL != rlm) {
	    __CFRunLoopModeUnlock(rlm);
	}
    }
    __CFRunLoopUnlock(rl);
    if (doVer0Callout) {
        // 核心操作6:如果标记为“移除成功时需要触发操作”,则触发_context.version0.cancel
        rls->_context.version0.cancel(rls->_context.version0.info, rl, modeName);	/* CALLOUT */
    }
    if (doRLSRelease) CFRelease(rls);
}
复制代码

2.2 Observers

添加目标 Observer 到指定的 Mode 的操作如下:

  • 如果目标 Observer 的_runLoop非空且不等于目标 RunLoop,则直接返回,以保证 Observer 只能添加到一个RunLoop中(与 Documentation 对 Observer 的描述一致);
  • 目标 Mode 为 CommonModes
    • 将目标 Source 添加到 commonModeItems 集合中
    • 将目标 Source 添加到 CommonModes 所包含的所有 Modes 中
  • 目标 Mode 不是 CommonModes:
    • 以目标 Mode 的_observers数组按_order降序的原则,将目标 Observer 插入_observers
    • 更新目标 Mode 的_observerMask
    • 更新目标 Observer 的_runLoop_rlCount

NOTE:_observers数组是始终按_order降序的,所以 Mode 中_order越大的 Observer,处理优先级越高。不过大部分情况下_order都会设置为 0。

// 省略掉一些简单的懒加载代码
void CFRunLoopAddObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFStringRef modeName) {
    CHECK_FOR_FORK();
    CFRunLoopModeRef rlm;
    if (__CFRunLoopIsDeallocating(rl)) return;
    // 核心操作0:保证Observer只能添加到一个RunLoop中
    if (!__CFIsValid(rlo) || (NULL != rlo->_runLoop && rlo->_runLoop != rl)) return;
    __CFRunLoopLock(rl);
    if (modeName == kCFRunLoopCommonModes) {
	CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
	
        ...
        
	CFSetAddValue(rl->_commonModeItems, rlo);
	if (NULL != set) {
	    CFTypeRef context[2] = {rl, rlo};
	    CFSetApplyFunction(set, (__CFRunLoopAddItemToCommonModes), (void *)context);
	    CFRelease(set);
	}
    } else {
	rlm = __CFRunLoopFindMode(rl, modeName, true);
	
        ...
        
	if (NULL != rlm && !CFArrayContainsValue(rlm->_observers, CFRangeMake(0, CFArrayGetCount(rlm->_observers)), rlo)) {
            Boolean inserted = false;
            // 核心操作1:以目标Mode的`_observers`数组按`_order`降序的原则插入`_observers`
            for (CFIndex idx = CFArrayGetCount(rlm->_observers); idx--; ) {
                CFRunLoopObserverRef obs = (CFRunLoopObserverRef)CFArrayGetValueAtIndex(rlm->_observers, idx);
                if (obs->_order <= rlo->_order) {
                    CFArrayInsertValueAtIndex(rlm->_observers, idx + 1, rlo);
                    inserted = true;
                    break;
                }
            }
            if (!inserted) {
	        CFArrayInsertValueAtIndex(rlm->_observers, 0, rlo);
            }
            // 核心操作2:更新目标Mode的`_observerMask`
	    rlm->_observerMask |= rlo->_activities;
            // 核心操作3:更新目标Observer的`_runLoop`和`_rlCount`
	    __CFRunLoopObserverSchedule(rlo, rl, rlm);
	}
        if (NULL != rlm) {
	    __CFRunLoopModeUnlock(rlm);
	}
    }
    __CFRunLoopUnlock(rl);
}

static void __CFRunLoopObserverSchedule(CFRunLoopObserverRef rlo, CFRunLoopRef rl, CFRunLoopModeRef rlm) {
    __CFRunLoopObserverLock(rlo);
    if (0 == rlo->_rlCount) {
	rlo->_runLoop = rl;
    }
    rlo->_rlCount++;
    __CFRunLoopObserverUnlock(rlo);
}
复制代码

将目标 Observer 从指定的 Mode 中移除的操作如下:

  • 目标 Mode 为 CommonModes
    • 将目标 Observer 从 commonModeItems 集合中移除
    • 将目标 Observer 从 CommonModes 所包含的所有 Modes 中移除
  • 目标 Mode 不是 CommonModes:
    • 将目标 Observer 从_observers中移除;
    • 更新目标 Observer 的_runLoop_rlCount
void CFRunLoopRemoveObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFStringRef modeName) {
    CHECK_FOR_FORK();
    CFRunLoopModeRef rlm;
    __CFRunLoopLock(rl);
    if (modeName == kCFRunLoopCommonModes) {
	if (NULL != rl->_commonModeItems && CFSetContainsValue(rl->_commonModeItems, rlo)) {
	    CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
	    CFSetRemoveValue(rl->_commonModeItems, rlo);
	    if (NULL != set) {
		CFTypeRef context[2] = {rl, rlo};
		CFSetApplyFunction(set, (__CFRunLoopRemoveItemFromCommonModes), (void *)context);
		CFRelease(set);
	    }
	} else {
	}
    } else {
	rlm = __CFRunLoopFindMode(rl, modeName, false);
	if (NULL != rlm && NULL != rlm->_observers) {
	    CFRetain(rlo);
            CFIndex idx = CFArrayGetFirstIndexOfValue(rlm->_observers, CFRangeMake(0, CFArrayGetCount(rlm->_observers)), rlo);
            if (kCFNotFound != idx) {
                // 核心操作1:将目标Observer从_observers中移除
                CFArrayRemoveValueAtIndex(rlm->_observers, idx);
                // 核心操作2:更新目标Observer的`_runLoop`和`_rlCount`
	        __CFRunLoopObserverCancel(rlo, rl, rlm);
            }
	    CFRelease(rlo);
	}
        if (NULL != rlm) {
	    __CFRunLoopModeUnlock(rlm);
	}
    }
    __CFRunLoopUnlock(rl);
}

static void __CFRunLoopObserverCancel(CFRunLoopObserverRef rlo, CFRunLoopRef rl, CFRunLoopModeRef rlm) {
    __CFRunLoopObserverLock(rlo);
    rlo->_rlCount--;
    if (0 == rlo->_rlCount) {
	rlo->_runLoop = NULL;
    }
    __CFRunLoopObserverUnlock(rlo);
}
复制代码

2.3 Timers

对于三种类型的监控对象的管理,其中对 Timers 的管理的最复杂的。所以下面的某些操作,在完全了解 Timers 的管理和响应机制之前是稍微比较晦涩的。可以先暂且撇开一些内部细节,先看它到底做了哪些事情。

添加目标 Timer 到指定的 Mode 的操作如下:

  • 如果目标 Timer 的_runLoop非空且不等于目标 RunLoop,则直接返回,以保证 Timer 只能添加到一个RunLoop中(与 Documentation 对 Timer 的描述一致);
  • 目标 Mode 为 CommonModes
    • 将目标 Timer 添加到 commonModeItems 集合中
    • 将目标 Timer 添加到 CommonModes 所包含的所有 Modes 中
  • 目标 Mode 不是 CommonModes:
    • 更新 Timer 的_runLoop_rlModes
    • 更新目标 Mode 的_timers的排序(包括“更新目标 Mode 的下一次计时事件触发点”操作);

NOTE:关于__CFRepositionTimerInMode__CFArmNextTimerInMode,本篇直接阐述其实现的效果,这块属于 RunLoop 的核心逻辑,会在下一篇学习 RunLoop 如何处理 Timer 时了解到为什么需要这两个方法。

// 省略掉一些简单的懒加载代码
void CFRunLoopAddTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeName) {    
    CHECK_FOR_FORK();
    if (__CFRunLoopIsDeallocating(rl)) return;
    if (!__CFIsValid(rlt) || (NULL != rlt->_runLoop && rlt->_runLoop != rl)) return;
    __CFRunLoopLock(rl);
    if (modeName == kCFRunLoopCommonModes) {
	CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
	
        ...
        
	CFSetAddValue(rl->_commonModeItems, rlt);
	if (NULL != set) {
	    CFTypeRef context[2] = {rl, rlt};
	    CFSetApplyFunction(set, (__CFRunLoopAddItemToCommonModes), (void *)context);
	    CFRelease(set);
	}
    } else {
	CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, true);
	
        ...
        
	if (NULL != rlm && !CFSetContainsValue(rlt->_rlModes, rlm->_name)) {
            __CFRunLoopTimerLock(rlt);
            //核心操作1:更新Timer的_runLoop和_rlModes
            if (NULL == rlt->_runLoop) {
		rlt->_runLoop = rl;
  	    } else if (rl != rlt->_runLoop) {
                __CFRunLoopTimerUnlock(rlt);
	        __CFRunLoopModeUnlock(rlm);
                __CFRunLoopUnlock(rl);
		return;
	    }
  	    CFSetAddValue(rlt->_rlModes, rlm->_name);
            __CFRunLoopTimerUnlock(rlt);
            __CFRunLoopTimerFireTSRLock();
            //核心操作2:更新目标Mode的_timers的排序
            __CFRepositionTimerInMode(rlm, rlt, false);
            __CFRunLoopTimerFireTSRUnlock();
            //NOTE: 操作系统版本兼容代码,不重要可以忽略
            if (!_CFExecutableLinkedOnOrAfter(CFSystemVersionLion)) {
                if (rl != CFRunLoopGetCurrent()) CFRunLoopWakeUp(rl);
            }
	}
        if (NULL != rlm) {
	    __CFRunLoopModeUnlock(rlm);
	}
    }
    __CFRunLoopUnlock(rl);
}
复制代码

将目标 Timer 从指定 Mode 中移除的操作如下:

  • 目标 Mode 为 CommonModes
    • 将目标 Timer 从 commonModeItems 集合中移除
    • 将目标 Timer 从 CommonModes 所包含的所有 Modes 中移除
  • 目标 Mode 不是 CommonModes:
    • 更新 Timer 的_runLoop_rlModes
    • “更新目标 Mode 的下一次计时事件触发点”;
void CFRunLoopRemoveTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeName) {
    CHECK_FOR_FORK();
    __CFRunLoopLock(rl);
    if (modeName == kCFRunLoopCommonModes) {
	if (NULL != rl->_commonModeItems && CFSetContainsValue(rl->_commonModeItems, rlt)) {
	    CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
	    CFSetRemoveValue(rl->_commonModeItems, rlt);
	    if (NULL != set) {
		CFTypeRef context[2] = {rl, rlt};
		CFSetApplyFunction(set, (__CFRunLoopRemoveItemFromCommonModes), (void *)context);
		CFRelease(set);
	    }
	} else {
	}
    } else {
	CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, false);
        CFIndex idx = kCFNotFound;
        CFMutableArrayRef timerList = NULL;
        if (NULL != rlm) {
            timerList = rlm->_timers;
            if (NULL != timerList) {
                idx = CFArrayGetFirstIndexOfValue(timerList, CFRangeMake(0, CFArrayGetCount(timerList)), rlt);
            }
        }
        if (kCFNotFound != idx) {
            __CFRunLoopTimerLock(rlt);
            //核心操作1:更新Timer的_runLoop和_rlModes
            CFSetRemoveValue(rlt->_rlModes, rlm->_name);
            if (0 == CFSetGetCount(rlt->_rlModes)) {
                rlt->_runLoop = NULL;
            }
            __CFRunLoopTimerUnlock(rlt);
	    CFArrayRemoveValueAtIndex(timerList, idx);
            //核心操作2:更新目标Mode的下一次计时事件触发点
            __CFArmNextTimerInMode(rlm, rl);
        }
        if (NULL != rlm) {
	    __CFRunLoopModeUnlock(rlm);
	}
    }
    __CFRunLoopUnlock(rl);
}
复制代码

三、CommonModes管理

总结第二章包含的 CommonModes 管理相关逻辑如下:

  • 添加操作目标 Mode 为 CommonModes:
    • 将目标对象添加到 commonModeItems 集合中;
    • 将目标对象添加到 CommonModes 所包含的所有 Modes 中;
  • 移除操作目标 Mode 为 CommonModes:
    • 将目标对象从 commonModeItems 集合中移除;
    • 将目标对象从 CommonModes 所包含的所有 Modes 中移除;

所调用的方法实现如下:

static void __CFRunLoopAddItemToCommonModes(const void *value, void *ctx) {
    CFStringRef modeName = (CFStringRef)value;
    CFRunLoopRef rl = (CFRunLoopRef)(((CFTypeRef *)ctx)[0]);
    CFTypeRef item = (CFTypeRef)(((CFTypeRef *)ctx)[1]);
    if (CFGetTypeID(item) == CFRunLoopSourceGetTypeID()) {
	CFRunLoopAddSource(rl, (CFRunLoopSourceRef)item, modeName);
    } else if (CFGetTypeID(item) == CFRunLoopObserverGetTypeID()) {
	CFRunLoopAddObserver(rl, (CFRunLoopObserverRef)item, modeName);
    } else if (CFGetTypeID(item) == CFRunLoopTimerGetTypeID()) {
	CFRunLoopAddTimer(rl, (CFRunLoopTimerRef)item, modeName);
    }
}

static void __CFRunLoopRemoveItemFromCommonModes(const void *value, void *ctx) {
    CFStringRef modeName = (CFStringRef)value;
    CFRunLoopRef rl = (CFRunLoopRef)(((CFTypeRef *)ctx)[0]);
    CFTypeRef item = (CFTypeRef)(((CFTypeRef *)ctx)[1]);
    if (CFGetTypeID(item) == CFRunLoopSourceGetTypeID()) {
	CFRunLoopRemoveSource(rl, (CFRunLoopSourceRef)item, modeName);
    } else if (CFGetTypeID(item) == CFRunLoopObserverGetTypeID()) {
	CFRunLoopRemoveObserver(rl, (CFRunLoopObserverRef)item, modeName);
    } else if (CFGetTypeID(item) == CFRunLoopTimerGetTypeID()) {
	CFRunLoopRemoveTimer(rl, (CFRunLoopTimerRef)item, modeName);
    }
}
复制代码

向 CommonModes 中添加 Mode 的代码如下。将目标 Mode 添加到 CommonModes 意味着:将 RunLoop 的_commonModeItems中的所有监控对象,添加到目标 Mode 中。

void CFRunLoopAddCommonMode(CFRunLoopRef rl, CFStringRef modeName) {
    CHECK_FOR_FORK();
    if (__CFRunLoopIsDeallocating(rl)) return;
    __CFRunLoopLock(rl);
    if (!CFSetContainsValue(rl->_commonModes, modeName)) {
	CFSetRef set = rl->_commonModeItems ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModeItems) : NULL;
	CFSetAddValue(rl->_commonModes, modeName);
	if (NULL != set) {
	    CFTypeRef context[2] = {rl, modeName};
            //核心操作1:将_commonModeItems的所有对象,添加到目标Mode中
	    CFSetApplyFunction(set, (__CFRunLoopAddItemsToCommonMode), (void *)context);
	    CFRelease(set);
	}
    } else {
    }
    __CFRunLoopUnlock(rl);
}

static void __CFRunLoopAddItemsToCommonMode(const void *value, void *ctx) {
    CFTypeRef item = (CFTypeRef)value;
    CFRunLoopRef rl = (CFRunLoopRef)(((CFTypeRef *)ctx)[0]);
    CFStringRef modeName = (CFStringRef)(((CFTypeRef *)ctx)[1]);
    if (CFGetTypeID(item) == CFRunLoopSourceGetTypeID()) {
	CFRunLoopAddSource(rl, (CFRunLoopSourceRef)item, modeName);
    } else if (CFGetTypeID(item) == CFRunLoopObserverGetTypeID()) {
	CFRunLoopAddObserver(rl, (CFRunLoopObserverRef)item, modeName);
    } else if (CFGetTypeID(item) == CFRunLoopTimerGetTypeID()) {
	CFRunLoopAddTimer(rl, (CFRunLoopTimerRef)item, modeName);
    }
}
复制代码

综上所述,向 CommonModes 添加某个监控对象意味着:RunLoop 在_commonModes的任意一个 Mode 下运行,都能触发该监控对象。之所以能实现这个效果源于以下三点:

  • 添加目标对象到 CommonModes 时,目标对象会被添加到 CommonModes 的所有 Modes 中;
  • 添加目标对象到 CommonModes 时,目标对象会被添加到 RunLoop 的 commonModeItems 中;
  • 添加目标 Mode 到 CommonModes 时,会将 commonModeItems 中的所有对象添加到目标 Mode 中;

总结

本篇学习了 RunLoop 的添加 Modes、添加删除监控对象以及添加 CommonModes 基本操作。关于 Timer 管理的一些细节问题,以及 RunLoop 的核心逻辑(RunLoopRun)在下篇继续学习。 本篇内容可能有点绕,最后画图帮助理解(彩色框和线表示当次操作所引入的对象或关系):

Mode和监控对象基本操作图示.png

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享