/** FBObjectiveCGraphElement specialization that can gather all references kept in ivars, as part of collection etc. */ @interfaceFBObjectiveCObject : FBObjectiveCGraphElement @end
/** * Returns a description of the \c Ivar layout for a given class. * * @param cls The class to inspect. * * @return A description of the \c Ivar layout for \e cls. */ OBJC_EXPORT const uint8_t * _Nullable class_getIvarLayout(Class _Nullable cls) OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
/** * Returns a description of the layout of weak Ivars for a given class. * * @param cls The class to inspect. * * @return A description of the layout of the weak \c Ivars for \e cls. */ OBJC_EXPORT const uint8_t * _Nullable class_getWeakIvarLayout(Class _Nullable cls) OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
所以,拿到 ivar 列表之后,我们只需遍历一遍所有的 ivar ,判断该 ivar 对应的布局位置是否为强引用即可。
// NSMapTable.h /* return an NSPointerFunctions object reflecting the functions in use. This is a new autoreleased object that can be subsequently modified and/or used directly in the creation of other pointer "collections". */ @property (readonly, copy) NSPointerFunctions *keyPointerFunctions; @property (readonly, copy) NSPointerFunctions *valuePointerFunctions;
// 是否强引用 value - (BOOL)_objectRetainsEnumerableValues { if ([self.object respondsToSelector:@selector(valuePointerFunctions)]) { NSPointerFunctions *pointerFunctions = [self.object valuePointerFunctions]; if (pointerFunctions.acquireFunction == NULL) { returnNO; } if (pointerFunctions.usesWeakReadAndWriteBarriers) { returnNO; } } // 默认为强引用(如 NSArray) returnYES; }
// 是否强引用key - (BOOL)_objectRetainsEnumerableKeys { if ([self.object respondsToSelector:@selector(pointerFunctions)]) { // NSHashTable and similar // If object shows what pointer functions are used, lets try to determine // if it's not retaining objects NSPointerFunctions *pointerFunctions = [self.object pointerFunctions]; if (pointerFunctions.acquireFunction == NULL) { returnNO; } if (pointerFunctions.usesWeakReadAndWriteBarriers) { // It's weak - we should not touch it returnNO; } }
if ([self.object respondsToSelector:@selector(keyPointerFunctions)]) { NSPointerFunctions *pointerFunctions = [self.object keyPointerFunctions]; if (pointerFunctions.acquireFunction == NULL) { returnNO; } if (pointerFunctions.usesWeakReadAndWriteBarriers) { returnNO; } } // 默认为强引用(如 NSDictionary) returnYES; }
总结: 通过遍历集合元素(包括 key 和 value ),并判断其是否为强引用,可以获取集合类强引用的所有元素。
/** * Sets an associated value for a given object using a given key and association policy. * * @param object The source object for the association. * @param key The key for the association. * @param value The value to associate with the key key for object. Pass nil to clear an existing association. * @param policy The policy for the association. For possible values, see “Associative Object Behaviors.” * * @see objc_setAssociatedObject * @see objc_removeAssociatedObjects */ OBJC_EXPORT void objc_setAssociatedObject(id _Nonnull object, constvoid * _Nonnull key, id _Nullable value, objc_AssociationPolicy policy) OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0, 2.0);
其中的 policy 用于设置引用类型,有如下取值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/* Associative References */
/** * Policies related to associative references. * These are options to objc_setAssociatedObject() */ typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) { OBJC_ASSOCIATION_ASSIGN = 0, /**< Specifies a weak reference to the associated object. */ OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, /**< Specifies a strong reference to the associated object. * The association is not made atomically. */ OBJC_ASSOCIATION_COPY_NONATOMIC = 3, /**< Specifies that the associated object is copied. * The association is not made atomically. */ OBJC_ASSOCIATION_RETAIN = 01401, /**< Specifies a strong reference to the associated object. * The association is made atomically. */ OBJC_ASSOCIATION_COPY = 01403/**< Specifies that the associated object is copied. * The association is made atomically. */ };