`
#import "TUTSimpleScatterPlot.h"
#import "CPDConstants.h"
#import "CPDStockPriceStore.h"
@implementation TUTSimpleScatterPlot
@synthesize hostView = _hostingView;
@synthesize graph = _graph;
@synthesize graphEmpActualWeightData = _graphEmpActualWeightData;
@synthesize graphEmpGoalWeightData = _graphEmpGoalWeightData;
// Initialise the scatter plot in the provided hosting view with the provided data.
// The data array should contain NSValue objects each representing a CGPoint.
-(id)initWithHostingView:(CPTGraphHostingView *)hostingView andEmpActualWeight:(NSMutableArray *)valuesEmpActualWeight andEmpGoalWeight:(NSMutableArray *)valuesEmpGoalWeight
{
self = [super init];
if ( self != nil ) {
self.hostView = hostingView;
self.graphEmpActualWeightData = valuesEmpActualWeight;
self.graphEmpGoalWeightData = valuesEmpGoalWeight;
self.graph = nil;
}
return self;
}
#pragma mark - Chart behavior
-(void)initPlot {
[self configureGraph];
[self configurePlots];
[self configureAxes];
}
-(void)configureGraph {
// 1 - Create the graph
CPTGraph *graph = [[CPTXYGraph alloc] initWithFrame:self.hostView.bounds];
[graph applyTheme:[CPTTheme themeNamed:kCPTDarkGradientTheme]];
self.hostView.hostedGraph = graph;
// 2 - Set graph title
NSString *title = @"Body weight actual and goal";
graph.title = title;
// 3 - Create and set text style
CPTMutableTextStyle *titleStyle = [CPTMutableTextStyle textStyle];
titleStyle.color = [CPTColor whiteColor];
titleStyle.fontName = @"Helvetica-Bold";
titleStyle.fontSize = 16.0f;
graph.titleTextStyle = titleStyle;
graph.titlePlotAreaFrameAnchor = CPTRectAnchorTop;
graph.titleDisplacement = CGPointMake(0.0f, 10.0f);
// 4 - Set padding for plot area
[graph.plotAreaFrame setPaddingLeft:30.0f];
[graph.plotAreaFrame setPaddingBottom:30.0f];
// 5 - Enable user interactions for plot space
CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *) graph.defaultPlotSpace;
plotSpace.allowsUserInteraction = YES;
}
-(void)configurePlots {
// 1 - Get graph and plot space
CPTGraph *graph = self.hostView.hostedGraph;
CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *) graph.defaultPlotSpace;
// 2 - Create the two plots
CPTScatterPlot *actualPlot = [[CPTScatterPlot alloc] init];
actualPlot.dataSource = self;
actualPlot.identifier = CPDTickerSymbolActual;
CPTColor *actualColor = [CPTColor redColor];
[graph addPlot:actualPlot toPlotSpace:plotSpace];
CPTScatterPlot *goalPlot = [[CPTScatterPlot alloc] init];
goalPlot.dataSource = self;
goalPlot.identifier = CPDTickerSymbolGoal;
CPTColor *goalColor = [CPTColor greenColor];
[graph addPlot:goalPlot toPlotSpace:plotSpace];
// 3 - Set up plot space
[plotSpace scaleToFitPlots:[NSArray arrayWithObjects:actualPlot,nil]];
CPTMutablePlotRange *xRange = [plotSpace.xRange mutableCopy];
[xRange expandRangeByFactor:CPTDecimalFromCGFloat(1.1f)];
plotSpace.xRange = xRange;
CPTMutablePlotRange *yRange = [plotSpace.yRange mutableCopy];
[yRange expandRangeByFactor:CPTDecimalFromCGFloat(1.2f)];
plotSpace.yRange = yRange;
// 4 - Create styles and symbols
CPTMutableLineStyle *actualLineStyle = [actualPlot.dataLineStyle mutableCopy];
actualLineStyle.lineWidth = 2.5;
actualLineStyle.lineColor = actualColor;
actualPlot.dataLineStyle = actualLineStyle;
CPTMutableLineStyle *actualSymbolLineStyle = [CPTMutableLineStyle lineStyle];
actualSymbolLineStyle.lineColor = actualColor;
CPTPlotSymbol *actualSymbol = [CPTPlotSymbol hexagonPlotSymbol];
actualSymbol.fill = [CPTFill fillWithColor:actualColor];
actualSymbol.lineStyle = actualSymbolLineStyle;
actualSymbol.size = CGSizeMake(6.0f, 6.0f);
actualPlot.plotSymbol = actualSymbol;
CPTMutableLineStyle *goalLineStyle = [goalPlot.dataLineStyle mutableCopy];
goalLineStyle.lineWidth = 1.0;
goalLineStyle.lineColor = goalColor;
goalPlot.dataLineStyle = goalLineStyle;
CPTMutableLineStyle *goalSymbolLineStyle = [CPTMutableLineStyle lineStyle];
goalSymbolLineStyle.lineColor = goalColor;
CPTPlotSymbol *goalSymbol = [CPTPlotSymbol starPlotSymbol];
goalSymbol.fill = [CPTFill fillWithColor:goalColor];
goalSymbol.lineStyle = goalSymbolLineStyle;
goalSymbol.size = CGSizeMake(6.0f, 6.0f);
goalPlot.plotSymbol = goalSymbol;
}
-(void)configureAxes {
// 1 - Create styles
CPTMutableTextStyle *axisTitleStyle = [CPTMutableTextStyle textStyle];
axisTitleStyle.color = [CPTColor whiteColor];
axisTitleStyle.fontName = @"Helvetica-Bold";
axisTitleStyle.fontSize = 12.0f;
CPTMutableLineStyle *axisLineStyle = [CPTMutableLineStyle lineStyle];
axisLineStyle.lineWidth = 2.0f;
axisLineStyle.lineColor = [CPTColor whiteColor];
CPTMutableTextStyle *axisTextStyle = [[CPTMutableTextStyle alloc] init];
axisTextStyle.color = [CPTColor whiteColor];
axisTextStyle.fontName = @"Helvetica-Bold";
axisTextStyle.fontSize = 11.0f;
CPTMutableLineStyle *tickLineStyle = [CPTMutableLineStyle lineStyle];
tickLineStyle.lineColor = [CPTColor whiteColor];
tickLineStyle.lineWidth = 2.0f;
CPTMutableLineStyle *gridLineStyle = [CPTMutableLineStyle lineStyle];
tickLineStyle.lineColor = [CPTColor blackColor];
tickLineStyle.lineWidth = 1.0f;
// 2 - Get axis set
CPTXYAxisSet *axisSet = (CPTXYAxisSet *) self.hostView.hostedGraph.axisSet;
// 3 - Configure x-axis
CPTAxis *x = axisSet.xAxis;
x.title = @"Weeks ->";
x.titleTextStyle = axisTitleStyle;
x.titleOffset = 15.0f;
x.axisLineStyle = axisLineStyle;
x.labelingPolicy = CPTAxisLabelingPolicyNone;
x.labelTextStyle = axisTextStyle;
x.majorTickLineStyle = axisLineStyle;
x.majorTickLength = 4.0f;
x.tickDirection = CPTSignNegative; //commented by me
// x.tickDirection = CPTSignPositive;
NSInteger xmajorIncrement = 2;
NSInteger xminorIncrement = 1;
//CGFloat dateCount = [[[CPDStockPriceStore sharedInstance] datesInMonth] count];
CGFloat dateCount = 20;
NSMutableSet *xLabels = [NSMutableSet setWithCapacity:dateCount];
NSMutableSet *xLocations = [NSMutableSet setWithCapacity:dateCount];
NSInteger i = 0;
for (NSString *date in [[CPDStockPriceStore sharedInstance] datesInMonth]) {
CPTAxisLabel *label = [[CPTAxisLabel alloc] initWithText:date textStyle:x.labelTextStyle];
CGFloat location = i++;
// CGFloat location = ++i;
label.tickLocation = CPTDecimalFromCGFloat(location);
label.offset = x.majorTickLength;
if (label) {
[xLabels addObject:label];
[xLocations addObject:[NSNumber numberWithFloat:location]];
}
}
x.axisLabels = xLabels;
x.majorTickLocations = xLocations;
// 4 - Configure y-axis
CPTAxis *y = axisSet.yAxis;
y.title = @"Weight ->";
y.titleTextStyle = axisTitleStyle;
y.titleOffset = -40.0f; //commented by me
y.axisLineStyle = axisLineStyle;
y.majorGridLineStyle = gridLineStyle;
y.labelingPolicy = CPTAxisLabelingPolicyNone;
y.labelTextStyle = axisTextStyle;
y.labelOffset = 16.0f;
y.majorTickLineStyle = axisLineStyle;
y.majorTickLength = 4.0f;
y.minorTickLength = 2.0f;
y.tickDirection = CPTSignPositive;
NSInteger majorIncrement = 40;
NSInteger minorIncrement = 20;
CGFloat yMax = 300.0f; // should determine dynamically based on max price
NSMutableSet *yLabels = [NSMutableSet set];
NSMutableSet *yMajorLocations = [NSMutableSet set];
NSMutableSet *yMinorLocations = [NSMutableSet set];
for (NSInteger j = minorIncrement; j <= yMax; j += minorIncrement) {
NSUInteger mod = j % majorIncrement;
if (mod == 0) {
CPTAxisLabel *label = [[CPTAxisLabel alloc] initWithText:[NSString stringWithFormat:@"%i", j] textStyle:y.labelTextStyle];
NSDecimal location = CPTDecimalFromInteger(j);
label.tickLocation = location;
label.offset = -y.majorTickLength - y.labelOffset;
if (label) {
[yLabels addObject:label];
}
[yMajorLocations addObject:[NSDecimalNumber decimalNumberWithDecimal:location]];
} else {
[yMinorLocations addObject:[NSDecimalNumber decimalNumberWithDecimal:CPTDecimalFromInteger(j)]];
}
}
y.axisLabels = yLabels;
y.majorTickLocations = yMajorLocations;
y.minorTickLocations = yMinorLocations;
}
#pragma mark - CPTPlotDataSource methods
-(NSUInteger)numberOfRecordsForPlot:(CPTPlot *)plot {
//return [[[CPDStockPriceStore sharedInstance] datesInMonth] count];
return 20;
}
-(NSNumber *)numberForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index {
NSInteger valueCount = [[[CPDStockPriceStore sharedInstance] datesInMonth] count];
// NSValue *value = [self.graphData objectAtIndex:index];
// CGPoint point = [value CGPointValue];
switch (fieldEnum) {
case CPTScatterPlotFieldX:
if (index < valueCount) {
//if( [plot.identifier isEqual:CPDTickerSymbolGoal] == YES)
return [NSNumber numberWithUnsignedInteger:index];
}
break;
case CPTScatterPlotFieldY:
if ([plot.identifier isEqual:CPDTickerSymbolActual] == YES ) {
//return [[[CPDStockPriceStore sharedInstance] monthlyPrices:CPDTickerSymbolAAPL] objectAtIndex:index];
if(index < [_graphEmpActualWeightData count]){
// return [_graphEmpActualWeightData objectAtIndex:index];
return (NSDecimalNumber *)[NSDecimalNumber numberWithDouble:[[_graphEmpActualWeightData objectAtIndex:index] doubleValue]];
}
else{
// return (NSNumber *) nil;
}
} else if ([plot.identifier isEqual:CPDTickerSymbolGoal] == YES) {
//return [[[CPDStockPriceStore sharedInstance] monthlyPrices:CPDTickerSymbolGOOG]
//return [_graphEmpGoalWeightData objectAtIndex:index];
return (NSDecimalNumber *)[NSDecimalNumber numberWithDouble:[[_graphEmpGoalWeightData objectAtIndex:index] doubleValue]];
}
break;
}
return [NSDecimalNumber zero];
}
// This does the actual work of creating the plot if we don't already have a graph object.
-(void)initialisePlot
{
// Start with some simple sanity checks before we kick off
if ( (self.hostView == nil) || (self.graphEmpGoalWeightData == nil) ) {
NSLog(@"TUTSimpleScatterPlot: Cannot initialise plot without hosting view or data.");
return;
}
if ( self.graph != nil ) {
NSLog(@"TUTSimpleScatterPlot: Graph object already exists.");
return;
}
[self initPlot];
}
「こんにちは、私は昨日からこの問題に苦しんでいます。必死にあなたの助けが必要です。私はコア プロットを初めて使用し、グラフに 2 番目のプロットを描画しようとするとクラッシュの問題に直面しています。毎回色々な理由が思い浮かびます。それらのいくつかを以下に貼り付けます。
1) *キャッチされない例外 'NSInvalidArgumentException' によるアプリの終了、理由: '-[__NSArrayM numberOfRecordsForPlot:]: 認識されないセレクターがインスタンス 0x726adc0 に送信されました'
2)EXC_BAD_ACCESS
3) *キャッチされない例外 'NSInvalidArgumentException' によりアプリを終了します。理由: '-[CALayerArray numberOfRecordsForPlot:]: 認識されないセレクターがインスタンス 0x769f5b0 に送信されました'
4) *キャッチされない例外 'NSInvalidArgumentException' によるアプリの終了、理由: '-[__NSDecimalNumber numberOfRecordsForPlot:]: 認識されないセレクターがインスタンス 0x726adc0 に送信されました'
私は自分のコードで何がうまくいかなかったのか本当にわかりません。私が