私は 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 コードで根本的に間違ったことをしていますが、実際には何が見えません。
誰でも問題を見つけられますか?