@@ -207,6 +207,8 @@ - (void) dealloc
207207 [super dealloc ];
208208}
209209
210+ // While exploring the observer graph, for dependencies, we use this to
211+ // detect cycles to prevent infinite recursion.
210212- (void ) beginDependencyExpansionScope
211213{
212214 GS_MUTEX_LOCK (_lock);
@@ -219,6 +221,8 @@ - (void) beginDependencyExpansionScope
219221 GS_MUTEX_UNLOCK (_lock);
220222}
221223
224+ /* Nodes (observable values) in the observer graph are uniquely identified
225+ * using a combination of the object pointer and the name of the value */
222226- (id ) dependencyKeyForObject : (id )object key : (NSString *)key
223227{
224228 return [NSArray arrayWithObjects:
@@ -227,7 +231,7 @@ - (id) dependencyKeyForObject: (id)object key: (NSString *)key
227231 nil ];
228232}
229233
230- - (void ) pushAncestorForNode : (_NSKVOKeyObserver *)keyObserver
234+ - (void ) pushObserverToCurrentAncestorStack : (_NSKVOKeyObserver *)keyObserver
231235{
232236 id ancestorKey = [self dependencyKeyForObject: keyObserver.object
233237 key: keyObserver.key];
@@ -236,7 +240,7 @@ - (void) pushAncestorForNode: (_NSKVOKeyObserver *)keyObserver
236240 GS_MUTEX_UNLOCK (_lock);
237241}
238242
239- - (void ) popAncestorForNode : (_NSKVOKeyObserver *)keyObserver
243+ - (void ) popObserverFromCurrentAncestorStack : (_NSKVOKeyObserver *)keyObserver
240244{
241245 id ancestorKey = [self dependencyKeyForObject: keyObserver.object
242246 key: keyObserver.key];
@@ -246,7 +250,7 @@ - (void) popAncestorForNode: (_NSKVOKeyObserver *)keyObserver
246250}
247251
248252// / Mark keypath as visited in the current dependency-expansion scope.
249- - (BOOL ) markDependentKeypathVisited : (NSString *)keypath
253+ - (BOOL ) checkDependencyForCycle : (NSString *)keypath
250254 forNode : (_NSKVOKeyObserver *)keyObserver
251255{
252256 NSString *dependentKey;
@@ -261,7 +265,7 @@ - (BOOL) markDependentKeypathVisited: (NSString *)keypath
261265 {
262266 BOOL isCycle = [_dependencyAncestorKeys containsObject: visitToken];
263267 GS_MUTEX_UNLOCK (_lock);
264- // If it's on the active ancestor stack, treat as true cycle and dedup.
268+ // If it's on the current ancestor stack, treat as cycle and dedup.
265269 // If it's already visited but not on stack, allow expansion to continue.
266270 return !isCycle;
267271 }
@@ -407,16 +411,17 @@ - (bool) isEmpty
407411 }
408412
409413 [observationInfo beginDependencyExpansionScope ];
410- [observationInfo pushAncestorForNode : keyObserver];
414+ [observationInfo pushObserverToCurrentAncestorStack : keyObserver];
411415 /* Don't allow our own key to be recreated. */
412- [observationInfo markDependentKeypathVisited : keyObserver.key
416+ [observationInfo checkDependencyForCycle : keyObserver.key
413417 forNode: keyObserver];
414418
419+ /* The observers, which affect us */
415420 dependentObservers =
416421 [NSMutableArray arrayWithCapacity: [valueInfluencingKeys count ]];
417422 for (NSString *dependentKeypath in valueInfluencingKeys)
418423 {
419- if ([observationInfo markDependentKeypathVisited : dependentKeypath
424+ if ([observationInfo checkDependencyForCycle : dependentKeypath
420425 forNode: keyObserver])
421426 {
422427 _NSKVOKeyObserver *dependentObserver
@@ -428,13 +433,10 @@ - (bool) isEmpty
428433 [dependentObservers addObject: dependentObserver];
429434 }
430435 }
431- else
432- {
433- }
434436 }
435437 keyObserver.dependentObservers = dependentObservers;
436438
437- [observationInfo popAncestorForNode : keyObserver];
439+ [observationInfo popObserverFromCurrentAncestorStack : keyObserver];
438440 [observationInfo endDependencyExpansionScope ];
439441 }
440442 }
0 commit comments