【问题标题】:Having trouble plotting the x vs. y graph on Stanford CS193P Assignment 3 (2016)在斯坦福 CS193P 作业 3 (2016) 上绘制 x 与 y 图时遇到问题
【发布时间】:2016-08-15 09:27:57
【问题描述】:

我是 iOS 开发的初学者。除了实际绘制 x 与 y 图之外,我已经在 iTunes U 上完成了 2016 年斯坦福 CS193P iOS 开发课程的作业 3(图形计算器)(手势、视图控制器、视图、segues 等)。我对将代码放置在何处以及如何执行此操作感到很困惑;以及 drawRect 将从哪里获取 y 值。我已经在互联网上搜索了很长时间的解决方案。我假设图形视图控制器的模型是 CalculatorBrain 或者可能是大脑的程序,但我不太确定视图将如何从 drawRect 函数与该控制器对话以获取 y 值一个点 x。如果你能让我走上正确的轨道,那将非常有帮助。我将在下面粘贴我的图形视图控制器和图形视图代码。提前致谢。

//GraphViewController

import UIKit

class GraphViewController: UIViewController {

    private var brain = CalculatorBrain()

    var program: [AnyObject]?

    @IBOutlet weak var graphView: GraphingView! {
        didSet {
            graphView.addGestureRecognizer(UIPinchGestureRecognizer(target: graphView, action: #selector (GraphingView.changeScale(_:))))
            graphView.addGestureRecognizer(UIPanGestureRecognizer(target: graphView, action: #selector(GraphingView.panView(_:))))
            graphView.addGestureRecognizer(UITapGestureRecognizer(target: graphView, action: #selector(GraphingView.doubleTapOrigin(_:))))
        }
    }
}




//GraphingView
import UIKit

@IBDesignable
class GraphingView: UIView {

    @IBInspectable var scale: CGFloat = 50 { didSet { setNeedsDisplay() } }
    @IBInspectable var linewidth: CGFloat = 2 { didSet { setNeedsDisplay() } }
    var origin: CGPoint! { didSet { setNeedsDisplay() } }

    /* Gesture Code

    func changeScale (recognizer: UIPinchGestureRecognizer) {
        switch recognizer.state {
        case .Changed,.Ended:
            scale *= recognizer.scale
            recognizer.scale = 1.0
        default:
            break
        }
    }

    func panView (recognizer: UIPanGestureRecognizer) {
        switch recognizer.state {
        case .Changed,.Ended:
            origin.x += recognizer.translationInView(self).x
            origin.y += recognizer.translationInView(self).y
            recognizer.setTranslation(CGPoint(x:0,y:0), inView: self)
        default:
            break
        }
    }

    func doubleTapOrigin (recognizer: UITapGestureRecognizer) {
        recognizer.numberOfTapsRequired = 2
        switch recognizer.state {
        case .Ended :
            origin = CGPoint(x: recognizer.locationInView(self).x, y:recognizer.locationInView(self).y)
        default: break
        }
    }
    */

    var axesDrawer = AxesDrawer()

    override func drawRect(rect: CGRect) {

        if origin == nil {
            origin = CGPoint(x: bounds.midX, y: bounds.midY)
        }
        axesDrawer.drawAxesInRect(rect, origin: origin, pointsPerUnit: scale)

        var pixelX = 0

        while pixelX <= bounds.maxX {

            //do some code to get value of y for current x from the brain in the view controller and plot it with UIBezierPath

            pixelX += 1/contentScaleFactor
        }

    }

}

【问题讨论】:

    标签: ios swift xcode cs193p


    【解决方案1】:

    更新答案 - 使用函数指针

    上一个答案是使用数据源的一种方法。它是按照 UITableViewController 获取数据的方式建模的。

    阅读作业,似乎教授希望您使用可选的函数指针。

    执行以下操作:

    1. GraphingView中创建一个可选变量来保存函数指针:

      var computeYForX: ((Double) -> Double)?
      
    2. didSet 应用于该变量,并在设置时调用self.setNeedsDisplay()。这将告诉 iOS 需要调用 drawRect

    3. 在您的计算器中绘制时,将GraphingViewcomputeYForX 属性设置为(Double) -&gt; Double 函数中的GraphViewController。如果要删除该功能(例如,当有人重置计算器时),请将属性设置为nil

    4. drawRect 中,检查以确保computeYForX 不是nil,然后再使用它来绘制函数图。使用 guardif let 在使用函数之前安全地解包。

    上一个答案 - 使用数据源

    您需要向您的GraphingView 添加一个数据源。首先定义一个名为GraphDataSource的协议:

    protocol GraphDataSource: class {
        func computeYforX(x: Double) -> Double
    }
    

    dataSource 属性添加到GraphingView

    class GraphingView: UIView {
        weak var dataSource: GraphDataSource?
    

    通过将GraphDataSource 添加到class 定义行、实现computeYForX() 并将自己设置为didSetgraphViewdataSource,让您的GraphViewController 实现该协议:

    class GraphViewController: UIViewController, GraphDataSource {
    
        private var brain = CalculatorBrain()
    
        var program: [AnyObject]?
    
        @IBOutlet weak var graphView: GraphingView! {
            didSet {
                graphView.dataSource = self
                graphView.addGestureRecognizer(UIPinchGestureRecognizer(target: graphView, action: #selector (GraphingView.changeScale(_:))))
                graphView.addGestureRecognizer(UIPanGestureRecognizer(target: graphView, action: #selector(GraphingView.panView(_:))))
                graphView.addGestureRecognizer(UITapGestureRecognizer(target: graphView, action: #selector(GraphingView.doubleTapOrigin(_:))))
            }
        }
    
        func computeYForX(x: Double) -> Double {
            // call the brain to calculate y and return it
        }
    }
    

    然后在drawRect,当你需要一个y值时,在dataSource上调用computeYForX()

    let y = dataSource?.computeYForX(x)
    

    【讨论】:

    • 非常感谢您的帮助。这是唯一的方法吗?它没有说明作业中的协议(据我所知,讲师在关于协议的讲座之前发布了作业)。我认为这让我感到困惑。
    • 我用另一种更符合教授意图的方法更新了答案。
    【解决方案2】:

    我使用了计算器大脑中的现有功能。具体来说,在大脑内部,我创建了一个公共方法,该方法基于程序进行计算,通过属性列表类型转换存储为任何对象(我们在保存/恢复部分进行了该操作)。所有的命令都在那里——我只是把它打包成一个方法。我在很多事情上都使用这种方法——所以我从不重写代码来评估一系列操作数。

    在公共接口中,这只是一个可以从任何大脑实例访问的函数。特别是,在准备 segue 到图形视图时,我将图形视图控制器指向了这个函数。我还通过了当时大脑中存在的程序,以便可以绘制任何在计算器中有效的表达式。后者对我来说是一个目标,因为它是有道理的。我想避免重写解释操作数的函数。

    图形视图需要一个函数(可以是大脑或任何其他规范)和一个绘制表达式所需的“程序”。所以它是一个需要特定形式来描述操作的通用类。我认为这是一个完全“合法”的解决方案。

    Drawrect 然后使用函数和程序来绘制曲线。

    【讨论】:

      猜你喜欢
      • 2020-02-23
      • 2017-01-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-13
      • 1970-01-01
      • 2020-09-13
      • 1970-01-01
      相关资源
      最近更新 更多