【问题标题】:How to use enumerateByteRangesUsingBlock in Objective-C?如何在 Objective-C 中使用 enumerateByteRangesUsingBlock?
【发布时间】:2015-03-23 05:28:35
【问题描述】:

方法enumerateByteRangesUsingBlock: 在类NSData 中,在Apple 文档中解释如下:

使用块枚举数据对象中的每个字节范围。
- (void)enumerateByteRangesUsingBlock:(void (^)(const void *bytes, NSRange byteRange, BOOL *stop))block

参数

block
应用于数组中字节范围的块。

该块接受三个参数:
bytes
当前范围的字节数。
byteRange
当前数据字节的范围。
stop
对布尔值的引用。该块可以将该值设置为 YES 以停止对数据的进一步处理。 stop 参数是一个 out-only 参数。您应该只在 Block 中将此布尔值设置为 YES。

讨论

对于接收器中的每个连续内存区域调用一次枚举块(对于连续的 NSData 对象总共调用一次),直到枚举完所有字节或将停止参数设置为 YES。

但我的问题是,该块何时执行?哪个方法负责为块提供参数bytesbyteRangestop?比如我想遍历bytes数组的一部分,应该怎么控制?

【问题讨论】:

    标签: ios objective-c nsdata


    【解决方案1】:

    bytesbyteRangestop 参数由 enumerateByteRangesUsingBlock 传递给您的块。您无需指定要遍历的字节 - 您使用此方法遍历所有字节(您可以通过 stop 提前终止)。

    举个简单的例子,假设你想搜索一些NSData 来寻找一个0xff。你可以使用 -

    NSInteger ffFound=NSNotFound;
    [myData enumerateByteRangesUsingBlock:^(const void *bytes, NSRange byteRange, BOOL *stop) {
       for (NSInteger i=0;i<byteRange.length;i++) {
          if (bytes[i]== 0xff) {
             ffFound=byteRange.location+i;
             *stop=YES;
             break;
          }
       }
    }];
    
    if (ffFound != NSNotFound) {
        NSLog(@"0xFF was found at location %ld",(long)ffFound);
    }
    

    【讨论】:

    • for 循环中的错字。 byteRange 应该是 byteRange.lengthi 应该是 NSInteger。此外,还有另一个大缺陷。 byteRange.location 并不总是 0。不要假设它会是。
    • 谢谢。解决了这个问题。我假设当前块的 *bytes 始终为 0。 - 所以字节[0]=myData[byteRange.location]。设置ffFound时会考虑byteRange.location@
    • @rmaddy 文档令人困惑,但它说字节是“当前范围的字节”。我在 Google 中找到了另一个示例,建议我应该使用 byteRange.location,而不是 0,但这对我来说没有意义 - 如果是这种情况,它将是“数据字节”,而不是“当前范围的字节”。意见?
    • 查看文档。它是“当前范围的字节”和“当前数据字节的范围”。假设数据有 100 个字节。它可能分为两块。第一个可能是前 40 个字节。 bytes 参数将是这 40 个字节,byteRange 将是 0,40。第二次传递bytes 参数将是接下来的 60 个字节,范围将是 40,60。在这两种情况下,范围的第一个字节都是索引 0,但 byteRange.location 两次都不是 0。所以你当前的代码应该可以工作。
    • 这是我的解释 - byteRange.location 会改变,但字节缓冲区总是从指针的偏移量 0 开始
    【解决方案2】:

    [NSData enumerateByteRangesUsingBlock:] 用于读取获取数据的连续内存区域,这意味着当迭代器遇到新块时,它将执行传递给它的块。

    除此之外,不保证block 会被多次调用(换句话说,数据可能不会被分片)传递给块的bytes 的大小将始终相同。

    NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://httpbin.org/image/png"]];
    
    [data enumerateByteRangesUsingBlock:^(const void *bytes, NSRange byteRange, BOOL *stop) {
        NSLog(@"You get the chunk in range: %@", NSStringFromRange(byteRange));
    }];
    

    或者,您还可以枚举数据并在每次迭代时读取固定大小的块;

    NSUInteger length = [data length];
    NSUInteger chunkSize = 1024;
    NSUInteger chunkOffset = 0;
    
    do {
        NSUInteger chunkSize = MIN(length - chunkOffset, chunkSize);
    
        NSData *chunk = [data subdataWithRange:NSMakeRange(chunkOffset, chunkSize)];
        chunkOffset = chunkOffset + chunkSize;
    
    } while (chunkOffset < length);
    

    【讨论】:

      【解决方案3】:

      其他答案都不错,但是这部分没有回答:

      块什么时候执行?

      该块将在-enumerateByteRangesUsingBlock: 返回之前立即执行一次或多次。

      您可能会感到困惑,因为许多采用块的方法都是异步的。他们返回但保留该块并继续在后台做一些工作(或监视一些事件或输入)并稍后调用该块。

      -enumerateByteRangesUsingBlock: 不是这样的。是同步的。它在返回给调用者之前完成所有工作。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-12-03
        • 2011-02-10
        • 2011-07-07
        • 2014-08-11
        • 1970-01-01
        相关资源
        最近更新 更多