Core-Plot:在块内调用Plot或Graph上的reloadData并不起作用

时间:2013-09-25 16:09:46

标签: ios objective-c core-plot novocaine

我希望能够在运行时在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 Squared Plot与我现在的需求无关,它只是一个参考。 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,我可以在绘图上调用重新加载后完美地读取更新的值。

  • 但是,这些更新的值未显示在图中。无论_plotIndizesAndVolume-Array中哪些值发生变化,该图仍然是在调用-reloadData之后的方式。

所以,从我所看到的:我可以正确访问数组,我可以正确地更新和读取新值,图仍然保持不变并且不会改变。我糊涂了。可能我仍然犯了一些随机的愚蠢错误,我只是没有看到它。

UPDATE2:

好吧,似乎我的问题不是reloadData本身,而是我称之为的地方。更多背景:我正在使用诺瓦卡因通过设备麦克风测量分贝。这很好用。然后,我想通过corePlot(我在上面描述)中在图形中可视化部分测量的dB。我有一个名为startMeasuring的方法,我称之为然后 - 显然 - 开始测量分贝。每当发生这种情况时,我将测量值​​设为_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,它确实是我想要它做的事情。为什么我不能在块内调用呢?

2 个答案:

答案 0 :(得分:3)

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

答案 1 :(得分:2)

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

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

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