Is this a sane Objective-C Block Implementation?

青春壹個敷衍的年華 提交于 2019-12-18 17:07:15

问题


I wanted a variation of NSRegularExpression's – stringByReplacingMatchesInString:options:range:withTemplate: method that takes a block instead of a template. The return value of the block would be used as the replacement value. This is more flexible than a template, as you can imagine. Sort of like using the /e modifier in Perl regular expressions.

So I wrote a category to add the method. This is what I came up with:

@implementation NSRegularExpression (Block)

- (NSString *)stringByReplacingMatchesInString:(NSString *)string
                                       options:(NSMatchingOptions)options
                                         range:(NSRange)range
                                    usingBlock:(NSString* (^)(NSTextCheckingResult *result))block
{
    NSMutableString *ret = [NSMutableString string];
    NSUInteger pos = 0;

    for (NSTextCheckingResult *res in [self matchesInString:string options:options range:range]) {
        if (res.range.location > pos) {
            [ret appendString:[string substringWithRange:NSMakeRange(pos, res.range.location - pos)]];
        }
        pos = res.range.location + res.range.length;
        [ret appendString:block(res)];
    }
    if (string.length > pos) {
        [ret appendString:[string substringFromIndex:pos]];
    }
    return ret;
}

@end

This is my first attempt to play with blocks in Objective C. It feels a little weird, but it seems to work well. I have a couple of questions about it, though:

  1. Does this seem like a sane way to implement such a method?
  2. Is there some way to implement its internals using -enumerateMatchesInString:options:range:usingBlock: ? I tried it, but could not assign to pos from within the block. But if there was a way to make it work, it'd be cool to also pass the NSMatchingFlags and BOOL and handle them in the same way as that method. Do-able?

Update

Thanks to the answer from Dave DeLong, I've got a new version using a block:

@implementation NSRegularExpression (Block)

- (NSString *)stringByReplacingMatchesInString:(NSString *)string
                                       options:(NSMatchingOptions)options
                                         range:(NSRange)range
                                    usingBlock:(NSString * (^)(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop))block
{
    NSMutableString *ret = [NSMutableString string];
    __block NSUInteger pos = 0;

    [self enumerateMatchesInString:string options:options range:range usingBlock:^(NSTextCheckingResult *match, NSMatchingFlags flags, BOOL *stop)
    {
        if (match.range.location > pos) {
            [ret appendString:[string substringWithRange:NSMakeRange(pos, match.range.location - pos)]];
        }
        pos = match.range.location + match.range.length;
        [ret appendString:block(match, flags, stop)];
    }];
    if (string.length > pos) {
        [ret appendString:[string substringFromIndex:pos]];
    }
    return [NSString stringWithString:ret];
}

@end

Works great, thanks!


回答1:


Being able to assign to pos from within the block would be as simple as changing the declaration from:

NSUInteger pos = 0;

To:

__block NSUInteger pos = 0;

More info on the __block keyword: __block Variables



来源:https://stackoverflow.com/questions/4475796/is-this-a-sane-objective-c-block-implementation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!