views:

528

answers:

1

I'm using a view controller i.e. ViewController:UIViewController and have another class GraphViewController:UIViewController .

How do I call an instance of GraphViewController and place it into my ViewController? I am currently trying to call the plot within my ViewController directly, but I want to make the graph modular so I don't have to copy code if I use the same graph again.

ViewController has methods

-(void) refreshGraph;
//Inhereted Methods
-(NSUInteger)numberOfRecordsForPlot:(CPPlot *)plot;
-(NSNumber *)numberForPlot:(CPPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index;

How do I move these methods to a separate class and then call it to get the same plot in my ViewController? I am sure there must be a thread on this somewhere but I can't seem to find it.

Edit:

Here's a clarification of my problem. My code works when I am adopting the CPPlotDataSource protocol and do all of the plot setup within one class. What I want to do is move all of the graph setup to another class to effectively separate all core-plot graph and setup functions from my main ViewController class.

Here is some of the relevant code for my main ViewController, RatesTickerViewController.h, and my GraphViewController, RatesTickerGraphController.h.

#import "RatesTickerViewController.h"

#import "Tick.h"


#import <Foundation/Foundation.h>

#define DEGREES_TO_RADIANS(__ANGLE__) ((__ANGLE__) / 180.0 * M_PI)

@implementation RatesTickerViewController
@synthesize graphController, graphView;

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
    [super viewDidLoad];

    RatesTickerGraphController *aGraphController = [[RatesTickerGraphController alloc] initWithNibName:@"RatesTickerViewController" bundle:[NSBundle mainBundle]];
    [self setGraphController:aGraphController];
    [aGraphController release];

    //self.graphView = self.graphController.layerHost;
    [self.graphController refreshGraph];

}

#pragma mark -
#pragma mark Plot Data Source Methods

-(NSUInteger)numberOfRecordsForPlot:(CPPlot *)plot {
    return [graphController.dataForPlot count];
}

-(NSNumber *)numberForPlot:(CPPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index 
{
    NSNumber *num = [[graphController.dataForPlot objectAtIndex:index] valueForKey:(fieldEnum == CPScatterPlotFieldX ? @"x" : @"y")];
    return num;
}

#pragma mark -
#pragma mark Set Rotation Orientation Methods

// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    return (interfaceOrientation == UIInterfaceOrientationPortrait ||
            interfaceOrientation == UIInterfaceOrientationLandscapeLeft || 
            interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
    if (fromInterfaceOrientation == UIInterfaceOrientationPortrait)
    {
        isShowingLandscapeView = YES;
        [self setViewToLandscape];
    } else {
        isShowingLandscapeView = NO;
        [self setViewToPortrait];
    }
}

- (void)didReceiveMemoryWarning {
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];

    // Release any cached data, images, etc that aren't in use.
}

- (void)viewDidUnload {
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
    [graphController release]; graphController = nil;
}


- (void)dealloc {
    [super dealloc];
}


@end

...

@implementation RatesTickerGraphController
@synthesize dataForPlot;
@synthesize layerHost;

- (void)viewDidLoad {
    [super viewDidLoad];
    isShowingLandscapeView = NO;

    [self refreshGraph];
}

- (void)refreshGraph {
    //Graph Plot
    if(!graph){
        // Create graph from theme
        graph = [[CPXYGraph alloc] initWithFrame:CGRectZero];
        CPTheme *theme = [CPTheme themeNamed:kCPDarkGradientTheme];
        [graph applyTheme:theme];
        CPLayerHostingView *hostingView = (CPLayerHostingView *)self.layerHost;
        hostingView.hostedLayer = graph;
        graph.paddingLeft = 5.0;
        graph.paddingTop = 5.0;
        graph.paddingRight = 5.0;
        graph.paddingBottom = 5.0;

        // Create a white plot area
        CPScatterPlot *boundLinePlot = [[[CPScatterPlot alloc] init] autorelease];
        boundLinePlot.identifier = @"White Plot";
        boundLinePlot.dataLineStyle.miterLimit = 0.0f;
        boundLinePlot.dataLineStyle.lineWidth = 2.0f;
        boundLinePlot.dataLineStyle.lineColor = [CPColor whiteColor];
        boundLinePlot.dataSource = self;
        [graph addPlot:boundLinePlot];

        // Do a grey gradient
        CPColor *areaColor1 = [CPColor grayColor];
        CPGradient *areaGradient1 = [CPGradient gradientWithBeginningColor:areaColor1 endingColor:[CPColor clearColor]];
        areaGradient1.angle = -90.0f;
        CPFill *areaGradientFill = [CPFill fillWithGradient:areaGradient1];
        boundLinePlot.areaFill = areaGradientFill;
        boundLinePlot.areaBaseValue = [[NSDecimalNumber zero] decimalValue];
    }

    // Setup plot space
    CPXYPlotSpace *plotSpace = (CPXYPlotSpace *)graph.defaultPlotSpace;
    plotSpace.allowsUserInteraction = NO;
    //Auto scale the plot space to fit the data
    [plotSpace scaleToFitPlots:[NSArray arrayWithObject:[graph plotAtIndex:0]]];
    CPPlotRange *xRange = plotSpace.xRange;
    [xRange expandRangeByFactor:CPDecimalFromDouble(1.25)];
    plotSpace.xRange = xRange;
    CPPlotRange *yRange = plotSpace.yRange;
    [yRange expandRangeByFactor:CPDecimalFromDouble(1.1)];
    plotSpace.yRange = yRange;

    // Axes
    CPXYAxisSet *axisSet = (CPXYAxisSet *)graph.axisSet;
    CPXYAxis *x = axisSet.xAxis;
    x.axisLineStyle = nil;

    CPXYAxis *y = axisSet.yAxis;
    y.minorTicksPerInterval = 0;
    y.orthogonalCoordinateDecimal = CPDecimalFromString(@"0");
    y.labelingPolicy = CPAxisLabelingPolicyAutomatic;

    // Add plot symbols
    CPLineStyle *symbolLineStyle = [CPLineStyle lineStyle];
    symbolLineStyle.lineColor = [CPColor blackColor];
    CPPlotSymbol *plotSymbol = [CPPlotSymbol ellipsePlotSymbol];
    plotSymbol.fill = [CPFill fillWithColor:[CPColor whiteColor]];
    plotSymbol.lineStyle = symbolLineStyle;
    plotSymbol.size = CGSizeMake(5.0, 5.0);
    //boundLinePlot.plotSymbol = plotSymbol;

}
#pragma mark -
#pragma mark Plot Data Source Methods

-(NSUInteger)numberOfRecordsForPlot:(CPPlot *)plot {
    return [dataForPlot count];
}

-(NSNumber *)numberForPlot:(CPPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index 
{
    NSNumber *num = [[dataForPlot objectAtIndex:index] valueForKey:(fieldEnum == CPScatterPlotFieldX ? @"x" : @"y")];
    return num;
}
A: 

If I understand you correctly, you'd like to have a generic view controller that sets up a Core Plot graph within its view, but you'd like to have that view be able to be located within other views. To do this, you could simply create an instance of your graph view controller within the view controller for the larger view, and add your graph view controller's view as a subview of the larger view controller's view.

As far as the passthrough delegate methods you describe, you could create a GraphViewControllerDelegate protocol that requires those two methods be implemented and create a delegate property on your GraphViewController that looks like the following:

id<GraphViewControllerDelegate> delegate;

Within your GraphViewController's implementation of the Core Plot delegate methods, simply have them call the delegate's implementation of those methods. Set your encompassing view controller to be the delegate of the GraphViewController and have it conform to the GraphViewControllerDelegate protocol by implementing those two methods.

Brad Larson
When you say to add subview within the larger controller's view, I tried putting this in -(void)viewDidLoad in my ViewController:[self.graphView addSubview:graphController.view];However, when I build and go, the designated view in IB, graphView, is not rendered. It's just a white box.
Kevin
@Kevin: You're providing too little information here to go off of. What is self.graphView? The graph should be contained within the view or a subview of your GraphViewController. Is an instance of CPLayerHostingView containing your graph present in the controller's view or a subview? Is everything wired up properly?
Brad Larson
self.graphView is a UIView for where the view from my GraphViewController should point to. An instance of CPLayerHostingView is located in my GraphViewController and wired up.What I'm uncertain about is how to assign the view of my GraphViewController to my UIView graphView.
Kevin
On closer inspection of the CPTestApp-IPhone example app, I noticed that the view property is wired to the CPLayerHostingView. This may lead to why my graph is not being displayed. Can you explain how this works considering UIView is not the same as CPLayerHostingView?
Kevin
@Kevin: CPLayerHostingView is a UIView subclass, so it can stand in for a UIView wherever one is needed. In the ScatterPlot.xib Interface Builder file, we simply set the class for the view that the view controller would use to be a CPLayerHostingView. The remainder of the graph setup is done in the CPTestAppScatterPlotController.
Brad Larson
@Brad: When I try to set the class for my GraphViewController.xib to CPLayerHostingView, IB doesn't allow me to wire that view to the File Owner's view. Basically, I can't do what was done in ScatterPlot.xib. How did you get around this?
Kevin
Is there an example besides CPTestApp-IPhone that I could reference? I might be going about this the wrong way.
Kevin
Yes, the AAPLot and StockPlot sample applications are also valid starting points. Also, there is a more recent tutorial here by Marc Hoffman: http://blogs.remobjects.com/blogs/mh/2010/01/26/p973
Brad Larson
As far as being unable to connect things in Interface Builder, try dragging the CPLayerHostingView.h header file into IB manually. IB sometimes has trouble picking up on custom UIView subclasses.
Brad Larson