2

私は Core Plot の使用を開始したばかりで、テスト用にCPTGraphHostingView単純なカスタム ビュー コントローラーに組み込み、Core Data fetchRequest からの値をプロットします (これは、1 日あたりの食事カロリー摂取量をグラフ化するアプリです)。

コードは主にここのチュートリアルから貼り付けられています。

問題は、View Controller をビューにプッシュすると、UI が約 2 秒間フリーズすることです (ナビゲーション コントローラーに埋め込まれています)。これはデバイス (iPhone 4S) で実行した場合です。

[CPTAxis layoutSublayers]Instruments でプロファイリングすると、メイン スレッドが と によってブロックされていることがわかり[CPTLayer drawInContext]ます。

遅延は、データセットが大きすぎるためではありません。現在、正確に 2 つのポイントが含まれています。グラフは非常に単純で、次のようになります。

ここに画像の説明を入力

ビュー コントローラの完全な実装:

インターフェース:

//
//  ICCaloriesGraphController.h
//  iCalories
//
//  Created by David Fearon on 22/08/2013.
//  Copyright (c) 2013 David Fearon. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "CorePlot-CocoaTouch.h"
#import "ICDatabaseBrain.h"
#import "Day.h"
#import "CalorieEntry.h"

@interface ICCaloriesGraphController : UIViewController<CPTPlotDataSource, NSFetchedResultsControllerDelegate>
@property (weak, nonatomic) IBOutlet CPTGraphHostingView *graphHostingView;
@property (nonatomic, retain)ICDatabaseBrain* sharedDatabaseBrain;
@property (nonatomic, retain)NSFetchedResultsController* resultsController;

@end

実装:

//
//  ICCaloriesGraphController.m
//  iCalories
//
//  Created by David Fearon on 22/08/2013.
//  Copyright (c) 2013 David Fearon. All rights reserved.
//

#import "ICCaloriesGraphController.h"

@interface ICCaloriesGraphController ()

@property int numberOfRecordsForPlot;
@property float maxDailyCaloriesInDataset;
@property NSArray* days;

@end

@implementation ICCaloriesGraphController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.sharedDatabaseBrain = [ICDatabaseBrain sharedDatabaseBrain];
    self.resultsController = self.sharedDatabaseBrain.fetchDaysResultsController;

    self.days = [self.resultsController fetchedObjects];
    self.numberOfRecordsForPlot = [self.days count];

    [self updateMaxDailyCaloriesInDataset];

    // Create a CPTGraph object and add to hostView
    CPTGraph* graph = [[CPTXYGraph alloc] initWithFrame:self.graphHostingView.bounds];
    self.graphHostingView.hostedGraph = graph;

    // Get the (default) plotspace from the graph so we can set its x/y ranges
    CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *) self.graphHostingView.hostedGraph.defaultPlotSpace;

    // Note that these CPTPlotRange are defined by START and LENGTH (not START and END) !!
    [plotSpace setYRange: [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat( 0 ) length:CPTDecimalFromFloat( self.maxDailyCaloriesInDataset )]];
    [plotSpace setXRange: [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat( 0 ) length:CPTDecimalFromFloat( self.numberOfRecordsForPlot )]];

    // Create the plot (we do not define actual x/y values yet, these will be supplied by the datasource...)
    CPTScatterPlot* plot = [[CPTScatterPlot alloc] initWithFrame:CGRectZero];

    // Let's keep it simple and let this class act as datasource (therefore we implement <CPTPlotDataSource>)
    plot.dataSource = self;

    // Finally, add the created plot to the default plot space of the CPTGraph object we created before
    [self.graphHostingView.hostedGraph addPlot:plot toPlotSpace:self.graphHostingView.hostedGraph.defaultPlotSpace];

}

-(void)viewWillAppear:(BOOL)animated{

    [super viewWillAppear:animated];

}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


-(NSUInteger)numberOfRecordsForPlot:(CPTPlot *)plotnumberOfRecords {
    return self.numberOfRecordsForPlot;
}


-(void)updateMaxDailyCaloriesInDataset{

    if (self.numberOfRecordsForPlot == 0){
        self.maxDailyCaloriesInDataset = 0;
        return;
    }

    int max = 0;

    for (Day* day in self.days) {

        //count the calories in the day:
        int calorieSum = 0;
        for (CalorieEntry* calorieEntry in [day.calorieEntries allObjects]) {
            calorieSum += calorieEntry.calories.intValue;
        }

        if(calorieSum > max) max = calorieSum;

    }

    self.maxDailyCaloriesInDataset = max;

}


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

    if (self.numberOfRecordsForPlot == 0){
        return 0;
    }

    if(fieldEnum == CPTScatterPlotFieldY){

        Day* day = [self.days objectAtIndex:index];

        //count the calories in the day:
        int calorieSum = 0;
        for (CalorieEntry* calorieEntry in [day.calorieEntries allObjects]) {
            calorieSum += calorieEntry.calories.intValue;
        }

        return [NSNumber numberWithInt:calorieSum];
        //TODO: Set range for y axis

    }

    if(fieldEnum == CPTScatterPlotFieldX){
        return [NSNumber numberWithInt: index];
    }else{
        NSLog(@"fieldEnum was neither CPTScatterPlotFieldY or CPTScatterPlotFieldX in numberForPlot:");
        return 0;
    }

}

@end

遅延は、Core Data コードとはまったく関係ありません。それはすべて正常に動作します。これをグーグルで検索すると、2 つのポイントしかないデータセットではなく、巨大なデータセットに関する問題のみが表示されます。明らかに、私は Core Plot コードで根本的に間違ったことをしていますが、実際には何が見えません。

誰でも問題を見つけられますか?

4

1 に答える 1

1

maxDailyCaloriesInDataset大きいですか?デフォルトの軸ラベリング ポリシーでは、軸に沿って 1 単位離れた目盛りとラベルを配置します。が大きい場合、yRange重複するラベルが多数作成され、非常に遅くなる可能性があります。アプリの要件に応じて、majorIntervalLengthラベルをあまり作成しないように を増やすか、ラベル付けポリシーを変更します。CPTAxisLabelingPolicyAutomatic良いCPTAxisLabelingPolicyEqualDivisions選択です。

于 2013-08-23T16:21:57.730 に答える