// Filter cycles that have been broken down since we found them. // These are false-positive that were picked-up and are transient cycles. NSMutableSet<NSArray<FBObjectiveCGraphElement *> *> *brokenCycles = [NSMutableSetset]; for (NSArray<FBObjectiveCGraphElement *> *itemCycle in allRetainCycles) { for (FBObjectiveCGraphElement*element in itemCycle) { if (element.object ==nil) { // At least one element of the cycle has been removed, thus breaking // the cycle. [brokenCycles addObject:itemCycle]; break; } } } [allRetainCycles minusSet:brokenCycles];
// Take next adjecent node to that child. Wrapper object can // persist iteration state. If we see that node again, it will // give us new adjacent node unless it runs out of them //取top节点的next节点,也就是这个object可能持有的对象。 FBNodeEnumerator*firstAdjacent = [top nextObject]; if (firstAdjacent) { //如果存在未访问到的节点 // Current node still has some adjacent not-visited nodes
BOOL shouldPushToStack =NO; // 检查是否已经访问过了 // Check if child was already seen in that path if ([objectsOnPath containsObject:firstAdjacent]) { // We have caught a retain cycle //如果该节点已经存在被访问过的对象中,说明构成了retain cycle // Ignore the first element which is equal to firstAdjacent, use firstAdjacent // we're doing that because firstAdjacent has set all contexts, while its // first occurence could be a root without any context NSUInteger index = [stack indexOfObject:firstAdjacent]; NSInteger length = [stack count] - index;
if (index ==NSNotFound) { // Object got deallocated between checking if it exists and grabbing its index shouldPushToStack =YES; } else { //计算出firstAdj出现的位置,同时计算出路径的长度,将这一系列的节点(object),也就是环,存放在array里面。 //将这个array存放到retainCycles集合中。 NSRange cycleRange =NSMakeRange(index, length); NSMutableArray<FBNodeEnumerator *> *cycle = [[stack subarrayWithRange:cycleRange] mutableCopy]; [cycle replaceObjectAtIndex:0 withObject:firstAdjacent];
// 1. Unwrap the cycle // 2. Shift to lowest address (if we omit that, and the cycle is created by same class, // we might have duplicates) // 3. Shift by class (lexicographically)
[retainCycles addObject:[self _shiftToUnifiedCycle:[self _unwrapCycle:cycle]]]; } } else { // Node is clear to check, add it to stack and continue shouldPushToStack =YES; }
if (shouldPushToStack) { if ([stack count] < stackDepth) { [stack addObject:firstAdjacent]; } } } else { // Node has no more adjacent nodes, it itself is done, move on [stack removeLastObject]; [objectsOnPath removeObject:top]; } } } return retainCycles; }
//将全部的强引用对象封装成FBObjectiveCGraphElement for (id<FBObjectReference> ref in strongIvars) { id referencedObject = [ref objectReferenceFromObject:self.object]; if (referencedObject) { NSArray<NSString *> *namePath = [ref namePath]; FBObjectiveCGraphElement*element =FBWrapObjectGraphElementWithContext(self, referencedObject, self.configuration, namePath); if (element) { [retainedObjects addObject:element]; } } }
if ([NSStringFromClass(aCls) hasPrefix:@"__NSCF"]) { /** If we are dealing with toll-free bridged collections, we are not guaranteed that the collection will hold only Objective-C objects. We are not able to check in runtime what callbacks it uses to retain/release (if any) and we could easily crash here. */ return [NSSet setWithArray:retainedObjects]; }
if (class_isMetaClass(aCls)) { // If it's a meta-class it can conform to following protocols, // but it would crash when trying enumerating returnnil; }
BOOL isKeyValued =NO; if ([aCls instancesRespondToSelector:@selector(objectForKey:)]) { isKeyValued =YES; }
/** This codepath is prone to errors. When you enumerate a collection that can be mutated while enumeration we fall into risk of crash. To save ourselves from that we will catch such exception and try again. We should not try this endlessly, so at some point we will simply give up. */ NSInteger tries =10; for (NSInteger i =0; i < tries; ++i) { // If collection is mutated we want to rollback and try again - let's keep refs in temporary set NSMutableSet*temporaryRetainedObjects = [NSMutableSet new]; @try { for (id subobject inself.object) { if (retainsKeys) { FBObjectiveCGraphElement*element =FBWrapObjectGraphElement(self, subobject, self.configuration); if (element) { [temporaryRetainedObjects addObject:element]; } } if (isKeyValued && retainsValues) { FBObjectiveCGraphElement*element =FBWrapObjectGraphElement(self, [self.object objectForKey:subobject], self.configuration); if (element) { [temporaryRetainedObjects addObject:element]; } } } } @catch (NSException*exception) { // mutation happened, we want to try enumerating again continue; }
// If we are here it means no exception happened and we want to break outer loop [retainedObjects addObjectsFromArray:[temporaryRetainedObjects allObjects]]; break; } }
// Grab a strong reference to the object, otherwise it can crash while doing // nasty stuff on deallocation __attribute__((objc_precise_lifetime)) id anObject = self.object;
for (id object in allRetainedReferences) { FBObjectiveCGraphElement *element = FBWrapObjectGraphElement(self, object, self.configuration); if (element) { [results addObject:element]; } }
/** BLOCK_HAS_CTOR - Block has a C++ constructor/destructor, which gives us a good chance it retains objects that are not pointer aligned, so omit them. !BLOCK_HAS_COPY_DISPOSE - Block doesn't have a dispose function, so it does not retain objects and we are not able to blackbox it. */ if ((blockLiteral->flags & BLOCK_HAS_CTOR) || !(blockLiteral->flags & BLOCK_HAS_COPY_DISPOSE)) { returnnil; }
//计算出需要填充的fake对象数量 // Figure out the number of pointers it takes to fill out the object, rounding up. const size_t elements = (blockLiteral->descriptor->size + ptrSize - 1) / ptrSize;
// 创建fack对象 // Create a fake object of the appropriate length. void *obj[elements]; void *detectors[elements];
for (size_t i = 0; i < elements; ++i) { FBBlockStrongRelationDetector *detector = [FBBlockStrongRelationDetector new]; obj[i] = detectors[i] = detector; } //调用dispose_helper,这时候会调用每个FBBlockStrongRelationDetector的release方法,这时候会将strong设置为YES @autoreleasepool { dispose_helper(obj); } // Run through the release detectors and add each one that got released to the object's // strong ivar layout. NSMutableIndexSet *layout = [NSMutableIndexSet indexSet]; //判断strong是否为YES,如果为YES表示为强引用,则将其添加到layout for (size_t i = 0; i < elements; ++i) { FBBlockStrongRelationDetector *detector = (FBBlockStrongRelationDetector *)(detectors[i]); if (detector.isStrong) { [layout addIndex:i]; } // Destroy detectors [detector trueRelease]; } return layout; }