1

几天来我一直在为此苦苦挣扎——我有一个自定义协议,它应该从我的一个模型(通过它的控制器)获取数据到绘制它的视图。

这是我的做法 - 一步一步:

在图形视图中,我声明协议如下:

@class GraphView;

@protocol GraphViewDataSource <NSObject>

-(CGFloat)yValueForGraphView:(GraphView *)sender usingXval:(CGFloat)xVal;

@end

然后我在 view.h 中声明一个属性

@interface GraphView : UIView

@property (nonatomic, weak) IBOutlet id <GraphViewDataSource> dataSource;

@end

我在 view.m 中综合了属性:

@synthesize dataSource=_dataSource;

然后在我的drawRect中,我调用这个方法从另一个控制器的模型中带回一个CGFloat:

-(void) drawRect:(CGRect)rect
{
//context stuff, setting line width, etc

CGPoint startPoint=CGPointMake(5.0, 6.0);

NSLog(@"first, y value is: %f", startPoint.y);

startPoint.y=[self.dataSource yValueForGraphView:self usingXval:startPoint.x]; //accessing delegate via property

NSLog(@"now the y value now is: %f", startPoint.y);

//other code..
}

现在在我的另一个视图控制器中,我正在导入 view.h 文件并声明它符合协议:

#import "GraphView.h"

@interface CalculatorViewController () <GraphViewDataSource>

为 GraphView 创建一个属性:

@property (nonatomic, strong) GraphView *theGraphView;

合成:

@synthesize theGraphView=_theGraphView;

现在在设置器中,我将当前控制器设置为数据源(也称为委托):

-(void) setTheGraphView:(GraphView *)theGraphView
{
    _theGraphView=theGraphView;
    self.theGraphView.dataSource=self;

}

我还将控制器设置为 prepareForSegue 中的委托(我在寻找修复程序时尝试过的事情之一):

-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.identifier isEqualToString:@"GraphViewController"])
    {
        self.theGraphView.dataSource=self;
    }
}

最后,我实现了所需的方法:

-(CGFloat)yValueForGraphView:(GraphView *)sender usingXval:(CGFloat)xVal
{
    CGFloat test=51.40; //just to test
    return test;
}

我在graphView的drawRect中从我的测试NSLog得到的输出是:

2012-10-25 20:56:36.352 ..[2494:c07] first, y value is: 6.000000
2012-10-25 20:56:36.354 ..[2494:c07] now the y value now is: 0.000000

这应该通过数据源返回 51.40,但事实并非如此。我不知道为什么!让我发疯,似乎我做的一切都是正确的。但是委托方法没有被调用。

我错过了什么愚蠢的事情吗?


附加信息 - 控制器和 GraphView 图表:

图形计算器

4

3 回答 3

1

图表有帮助!

您需要做的是在您的 GraphViewController 上有一个方法,该方法可以公开您的自定义 GraphView,或者将委托设置在其中。在 segue 上,您需要访问目标视图控制器(GraphViewController),然后直接在 GraphView 中设置委托或将 self 传递给 GraphViewController 并让它设置委托。

在 CalculatorViewController 拥有的 GraphView 中设置委托不会影响 GraphViewController 中的 GraphView,除非 GraphView 是单例,或者被传递到 GraphViewController。

假设您的 GraphViewController 公开了一个属性,即它包含的 GraphView,则 CalculatorViewController 中的 segue 应该类似于...

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    // Ensure the identifier string matches the segue name from the Storyboard
    if ([segue.identifier isEqualToString:@"GraphViewControllerSegue"])
    {
        // Change this to whatever class is the destination class of the segue
        GraphViewController *graphViewController = (GraphViewController *)[segue destinationViewController];
        self.graphView.delegate = self;
        // Pass the GraphView with the delegate set into the GraphViewController
        graphViewController.graphView = self.graphView;
    }
}

它是按钮与动作的直接分隔这一事实是无关紧要的。如果你在 Storyboard/XIB 中给了 segue 一个标识符,那么prepareForSegue:sender:它就会被调用,我们可以确定调用的是什么 segue。

如果您的 GraphViewController 中没有用于 GraphView 的公共属性...

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.identifier isEqualToString:@"GraphViewControllerSegue"])
    {
        // Change this to whatever class is the destination class of the segue
        GraphViewController *graphViewController = (GraphViewController *)[segue destinationViewController];
        [graphViewController setGraphViewDelegate:self];
    }
}

并且您在 GraphViewController 实现中需要以下内容。

- (void)setGraphViewDelegate:(id)graphViewDelegate {
    // Set the delegate directly in the ivar
    _graphView.delegate = graphViewDelegate;
}
于 2012-10-28T22:53:49.273 回答
0

我解决这个问题的方法是链接一些代表,我用以下方法GraphView声明:protocol GraphViewDelegate

-(float)ordinateForAbscissa:(float)abscissa forGraph:(GraphView *)requestor;
-(float)scaleForGraph(GraphView *)requestor;

该协议由 实现,并且当控制器加载时GraphViewController,他将自己设置delegate为。GraphViewviewDidLoad

现在我有另一个委托,CalculatorControllerDelegateyCoordinateForX是从ordinateForAbscissa. CalculatorViewController实现此协议,并在 segueing 将自己设置为GraphViewController的委托时。

希望这可以帮助。

于 2012-10-30T00:42:39.743 回答
0

这是最终的解决方案:

GraphViewController 必须首先设置 GraphView 的委托。那是因为 graphView 连接到 GraphViewController(作为自定义 UIView),并且我发现无法从其他类设置 graphView 的特定实例不可用。

将信息获取到自定义视图(在我的例子中是 graphView)的方法是在自定义视图的控制器中设置另一个协议。然后将另一个类设置为该控制器的委托,并首先将数据传递给控制器​​,然后再传递给自定义视图。

一件非常重要的事情是,在使用情节提要时,控制器的委托应在 prepareForSegue 中设置(如 reckerbh 所述)。在我的例子中,CalculatorViewController 连接到 GraphViewController 所以我的 perpareForSegue 看起来像这样:

-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.identifier isEqualToString:@"ShowGraph"])
    {
        GraphViewController *gvc=[segue destinationViewController];
        gvc.yValueSource=self;
    }
}

请注意,我正在通过 [segue destinationViewController] 创建指向 GraphViewController 现有实例的新指针。我不是通过 alloc init 创建一个新的,因为它不会连接到我已经拥有的并且完全不相关。

所以我想这里的主要建议是确保在设置委托时使用相同的实例。如果您无法访问该实例,请使用双重授权(如果必须的话,我猜甚至可以使用三重授权)。

于 2012-10-30T22:55:45.103 回答