Skip to content

Instantly share code, notes, and snippets.

@zuccoi
Created October 6, 2012 01:20
Show Gist options
  • Save zuccoi/3843360 to your computer and use it in GitHub Desktop.
Save zuccoi/3843360 to your computer and use it in GitHub Desktop.
Category methods to traverse object graph and view tree.
#import <Foundation/Foundation.h>
// RLTraverseObjectGraphBlock
typedef void (^RLTraverseObjectGraphBlock)(id obj, NSUInteger depth, NSUInteger idx, id parent, BOOL *stop); // If you want to stop traversing completely, set YES to *stop.
// RLChildrenGetter
typedef id (^RLChildrenGetter)(id obj, NSUInteger depth, NSUInteger idx, id parent); // Return object which responds to enumerateObjetsUsingBlock: method. If you don't want to dive deeper, return nil.
@interface NSObject (RLTraverse)
- (void)traverseObjectGraphUsingBlock:(RLTraverseObjectGraphBlock)block childrenGetter:(RLChildrenGetter)childrenGetter;
@end
#import "NSObject+RLTraverse.h"
@implementation NSObject (RLTraverse)
- (BOOL)_traverseObjectGraphUsingBlock:(RLTraverseObjectGraphBlock)block childrenGetter:(RLChildrenGetter)childrenGetter depth:(NSUInteger)depth index:(NSUInteger)index parent:(id)parent
{
__block BOOL stopped = NO;
// Execute block
block(self, depth, index, parent, &stopped);
if (stopped) {
return YES;
}
// Enumerate children
if (childrenGetter) {
id children;
children = childrenGetter(self, depth, index, parent);
if ([children respondsToSelector:@selector(enumerateObjectsUsingBlock:)]) {
[children enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
stopped = [obj _traverseObjectGraphUsingBlock:block childrenGetter:childrenGetter depth:(depth + 1) index:idx parent:self];
if (stopped) {
*stop = stopped;
}
}];
}
}
return stopped;
}
- (void)traverseObjectGraphUsingBlock:(RLTraverseObjectGraphBlock)block childrenGetter:(RLChildrenGetter)childrenGetter
{
// Call primitive method
[self _traverseObjectGraphUsingBlock:block childrenGetter:childrenGetter depth:0 index:0 parent:nil];
}
@end
#import <UIKit/UIKit.h>
// RLTraverseViewTreeBlock
typedef void (^RLTraverseViewTreeBlock)(UIView *view, NSUInteger depth, NSUInteger idx, BOOL *stop);
@interface UIView (RLTraverse)
- (void)traverseViewTreeUsingBlock:(RLTraverseViewTreeBlock)block;
@end
#import "NSObject+RLTraverse.h"
#import "UIView+RLTraverse.h"
@implementation UIView (RLTraverse)
- (void)traverseViewTreeUsingBlock:(RLTraverseViewTreeBlock)block
{
// Traverse view tree
[self
traverseObjectGraphUsingBlock:^(id obj, NSUInteger depth, NSUInteger idx, id parent, BOOL *stop) {
block(obj, depth, idx, stop);
}
childrenGetter:^(UIView *view, NSUInteger depth, NSUInteger idx, id parent) {
return view.subviews;
}
];
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment