带有块和停止参数的递归方法

时间:2014-03-17 18:58:09

标签: ios objective-c recursion uiview objective-c-blocks

我在UIView上写了一个允许我走视图层次结构的类别:

的UIView + capture.h中

typedef void(^MSViewInspectionBlock)(UIView *view, BOOL *stop);

@interface UIView (Capture)

- (void)inspectViewHeirarchy:(MSViewInspectionBlock)block;

@end

的UIView + Capture.m

@implementation UIView (Capture)

- (void)inspectViewHeirarchy:(MSViewInspectionBlock)block
{
    BOOL stop = NO;
    [self inspectViewHeirarchy:block stop:stop];
}

#pragma - Private

- (void)inspectViewHeirarchy:(MSViewInspectionBlock)block stop:(BOOL)stop
{
    if (!block || stop) {
        return;
    }
    block(self, &stop);
    for (UIView *view in self.subviews) {
        [view inspectViewHeirarchy:block stop:stop];
        if (stop) {
            break;
        }
    }
}

@end

您可以这样使用:

[[[UIApplication sharedApplication] keyWindow] inspectViewHeirarchy:^(UIView *view, BOOL *stop) {
    if ([view isMemberOfClass:[UIScrollView class]]) {
        NSLog(@"Found scroll view!");
        *stop = YES;
    }
}];

除了将stop设置为YES之外,一切正常。这似乎完全没有任何影响。理想情况下,我希望停止递归,所以当我发现视图时,我想采取一些操作,我不必继续遍历视图层次结构的其余部分。 / p>

在使用积木时,我非常密集,所以它可能是非常明显的东西。任何帮助将不胜感激。

6 个答案:

答案 0 :(得分:4)

您使用块的方式与使用C函数完全相同。所以你真的不需要知道关于积木的事情。您的代码应该可以运行,但请注意将stop作为BOOL *传递给您的块并在您递归时创建新的本地区别。

您好像希望调用inspectViewHierarchy:stop:来影响外部stop变量。除非您将其作为参考传递,否则不会发生这种情况。所以我认为你想要的是:

- (void)inspectViewHeirarchy:(MSViewInspectionBlock)block stop:(BOOL *)stop

......以及适当的其他变化。

答案 1 :(得分:3)

我假设您希望在用户将inspectViewHierarchy设置为stop时从顶级YES返回。

(顺便说一句,你拼错了“层次结构”错误,你应该在你添加到标准类的方法上使用前缀。)

@implementation UIView (Capture)

- (void)micpringle_visitSubviewsRecursivelyWithBlock:(MSViewInspectionBlock)block
{
    BOOL stop = NO;
    [self inspectViewHierarchy:block stop:&stop];
}

#pragma - Private

- (void)micpringle_visitSubviewsRecursivelyWithBlock:(MSViewInspectionBlock)block stop:(BOOL *)stop
{
    block(self, stop);
    if (*stop)
        return;
    for (UIView *view in self.subviews) {
        [view micpringle_visitSubviewsRecursivelyWithBlock:block stop:stop];
        if (*stop)
            break;
    }
}

@end

答案 2 :(得分:2)

- (BOOL) inspectViewHeirarchy:(MSViewInspectionBlock)block
{
    BOOL stop = NO;
    block(self, &stop);
    if (stop)
       return YES;

    for (UIView *view in self.subviews) {
        if ([view inspectViewHeirarchy:block])
            return YES;
    }
    return NO;
}

答案 3 :(得分:1)

你不想在调用块后直接检查'stop'的状态吗?在调用inspectViewHierarchy之后调用它是没有用的:stop:因为你将'stop'的副本传递给该方法而不是引用。

答案 4 :(得分:0)

试试这个:

- (void)inspectViewHeirarchy:(MSViewInspectionBlock)block
{
    __block BOOL stop = NO;
    [self inspectViewHeirarchy:block stop:stop];
}

答案 5 :(得分:0)

块本质上会复制声明它们的变量和上下文。

即使您将布尔值作为参考传递,也可能是它使用了上下文的副本而不是真正的停止。

这只是一个疯狂的猜测,但是在inspectViewHierarchy中:stop:做类似的事情:

- (void)inspectViewHeirarchy:(MSViewInspectionBlock)block stop:(BOOL)stop
{
    if (!block || stop) {
        return;
    }

    // Add these changes
    __block BOOL blockStop = stop;
    block(self, &blockStop);

    for (UIView *view in self.subviews) {
        [view inspectViewHeirarchy:block stop:stop];

        if (stop) {
            break;
        }
    }
}

这可能是一个很长的镜头而且我不能100%确定它会在没有你的项目的情况下工作,但它值得一试。

另外,重构你的方法,所以“heirarchy”实际拼写为“层次结构”:]这对于可重用性和保持良好的代码库是好的;)