【问题标题】:Core-Plot: calling reloadData on Plot or Graph from within block doesn't workCore-Plot:从块内调用 Plot 或 Graph 上的 reloadData 不起作用
【发布时间】:2013-09-25 16:09:45
【问题描述】:

我希望能够在运行时更新/重新加载 iOS 设备上的 ScatterPlot。具体来说,我记录音频输入,做一些有趣的事情,并将结果作为一个简单的 NSNumber 值放入一个数组中。每当发生这种情况时,都会在我要更新的 Plot 上调用 reloadData,但遗憾的是,完全没有任何反应。基本上,我做的和这里的答案中描述的一样:real time plotting on iPhone using core plot?。它只是不起作用,所以我认为我犯了一些愚蠢的错误。

这是相关的方法:

-(NSNumber *) numberForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index {

    double val = (index/5.0) -10;

    if (fieldEnum == CPTScatterPlotFieldX) {
        return [NSNumber numberWithDouble:val];
    } else {
        if ([plot.identifier isEqual: @"X Squared Plot"]) {
            return [NSNumber numberWithDouble:10-(0.25*val*val)];
        } else if( [plot.identifier isEqual:@"LivePlot"]) {
            if (!_isMeasuring) {
                return [NSNumber numberWithFloat:0.0f];
            } else {
                printf("%f", [[_plotIndizesAndVolume objectAtIndex:index] floatValue]);
                return [NSNumber numberWithFloat:[[_plotIndizesAndVolume objectAtIndex:index] floatValue]];
            }
        } else {
            return 0;
        }
    }
}

X 平方图目前与我的需求无关,它只是一个参考。 LivePlot 是我需要并想要更新的。 _plotIndizesAndVolume 是我存储我的值的 NSMutableArray。它有 500 个元素,所有这些元素都在我执行开始时用 [NSNumber numberWithFloat:0.0f] 初始化。 Plot 也有 500 个 indizes,因此我们不会越界或其他什么。

代码执行良好,方法被调用,printf 语句工作并正确显示浮点数,Plot 只是没有更新。

我也试过

if (index < [_plotIndizesAndVolume count]) {
    return [NSNumber numberWithFloat:[_plotIndizesAndVolume objectAtIndex:index]];
} else {
    return [NSNumber numberWithFloat:0.0f];
}

数组中没有 500 个 0.0fs,所以我只是访问不同于 0.0f 的值。这当然更好,它也不起作用。

有什么想法吗?

更新1:

  • 如果我在应用程序开始时仅用随机数填充 _plotIndizesAndVolume,则绘图完全符合这些数字。

  • 如果我在方法中使用 printf,一旦在绘图上调用了 reload,我就可以完美地读取更新的值。

  • 但是,这些更新后的值不会显示在图中。无论 _plotIndizesAndVolume-Array 中的哪些值发生更改,绘图都将保持在其上调用 -reloadData 后的状态。

所以,据我所知:我可以正确访问数组,可以正确更新和读取新值,绘图仍然保持不变并且不会改变。我很困惑。可能我还是犯了一些随机的愚蠢错误,我只是没看到。

更新2:

好吧,似乎我的问题不是 reloadData 本身,而是我从哪里调用它。更多背景信息:我正在使用 novocaine 通过设备麦克风测量分贝。这工作正常。然后,我想通过 corePlot(我在上面描述过)在图表中可视化部分测量的 dB。我有一个名为startMeasuring 的方法,我有时会调用它,然后 - 显然 - 开始测量分贝。每当发生这种情况时,我都会将测量值 int _plotIndicesAndVolume 并在绘图上调用 reloadData

该方法如下所示(大部分直接从 novocain 示例中复制):

-(void) startMeasuring {

    if (_isMeasuring) {
        return;
    }

    __weak ViewController * wself = self;

    self.ringBuffer = new RingBuffer(32768, 2);
    self.audioManager = [Novocaine audioManager];

    // MEASURE SOME DECIBELS!
    // ==================================================
    __block float dbVal = 0.0;
    __block int count = 0;
    __block int limiter = 0;
    [self.audioManager setInputBlock:^(float *data, UInt32 numFrames, UInt32 numChannels) {

        vDSP_vsq(data, 1, data, 1, numFrames*numChannels);
        float meanVal = 0.0;
        vDSP_meanv(data, 1, &meanVal, numFrames*numChannels);

        float one = 1.0;
        vDSP_vdbcon(&meanVal, 1, &one, &meanVal, 1, 1, 0);
        dbVal = dbVal + 0.2*(meanVal - dbVal);

        float reducedVal = (dbVal + 66.0f)/3;

        if (!wself.measuringPaused && limiter > 10) {
            [wself.plotIndizesAndVolume replaceObjectAtIndex:count withObject:[NSNumber numberWithFloat:reducedVal]];
            [[wself.graph plotWithIdentifier:@"LivePlot"] reloadData];
            limiter = -1;
            ++count;
        }
        ++limiter;

    }];

    [self.audioManager play];

    _isMeasuring = true;

}

我从测量块中调用reloadData。我不太了解使用块,我只是假设我可以做到这一点。但是,如果我尝试更改数组中的数据,然后从其他地方手动重新加载绘图,它会起作用并且绘图会相应地更新。问题是否与我在块内调用方法有关?

即便如此,我仍然不确定为什么它不起作用,因为 printf 语句可以完美运行 - 所以我假设 updateData 方法已正确调用并且值已正确更新。

更新 3:

如果我在测量期间从其他地方调用reloadData,则图表会根据_plotIndizesAndVolume 中的内容更新得很好。如果我从块内调用它,它根本不会更新(即使我从块内调用另一个方法,而该方法又调用reloadData)。但是,我需要实时更新。我想我也可以每 x 毫秒重新加载一次绘图(接下来会尝试),我仍然很好奇为什么它一开始就不起作用。

更新 4:如更新 3 中所假设的,如果我通过 NSTimer 从其他地方调用 reloadData,它会完全按照我的意愿执行。那为什么我不能从块内调用它呢?

【问题讨论】:

  • 这与未出现的情节无关,但您应该直接返回[_plotIndizesAndVolume objectAtIndex:index],而不是将其转换为浮点数并直接返回NSNumber。它将运行得更快,并使您的代码更易于阅读。
  • 绘图空间的xRangeyRange 是否设置为使数据落在范围内?例如,对于 500 个数据点,xRange 的位置应为 -10,长度为 100 以适合所有点。
  • @EricSkroch NSNumber->float->NSNumber 转换只是我试图找出代码处理数组对象的方式是否有错误(因为 objectAtIndex: 返回一个 id),我根本无法想象,但我想尝试每一种可能性,即使是那些我认为愚蠢的可能性。关于 xRange:这对于“展示”部分情节不应该很重要吗?我展示情节的哪些部分并不重要,根本没有任何变化。还是我的假设有误?

标签: ios objective-c core-plot novocaine


【解决方案1】:

从主线程调用-reloadData(和任何其他Core Plot 方法)。

【讨论】:

  • 正如我在更新 4 中所说,这正是我所做的。为什么会这样呢?
  • 计时器在主线程上触发其目标方法。除非您可以保证该块将始终在主线程上执行,否则您应该确保对 reloadData in 的调用在主线程上执行。有几种方法可以做到这一点,包括-performSelectorOnMainThread:withObject:waitUntilDone: 和 GCD。
【解决方案2】:

您可能需要在计时器中更新绘图空间 x-range/y-range

CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *)self.graph.defaultPlotSpace;
[plotSpace scaleToFitPlots:[self.graph allPlots]];

CPTPlot *thePlot   = [self.graph plotWithIdentifier:kIdentifier];
[thePlot reloadData];

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多