0

In my current swift program, one function display real time acceleration data on screen with line. So I used class drawRect. As a result, the acceleration figure can be drawn, but not real time everytime I refresh it (turn down the App and reopen). I know that I should use some method such as setNeedsDisplay() to redraw it. But it was no use. Maybe I wrote it in a wrong way. Here is my code:

import UIKit

import CoreMotion

class draw: UIView, UIAccelerometerDelegate {

     var motionManager = CMMotionManager()

     override func drawRect(rect: CGRect) {

         motionManager.deviceMotionUpdateInterval = 0.1

        var acc_x: Double = 0.0

        var temp_x: Double = 0.0

        var i: CGFloat = 0

        var accLine_x = UIGraphicsGetCurrentContext()

        if(motionManager.deviceMotionAvailable) {

            var queue = NSOperationQueue.mainQueue()

            motionManager.startDeviceMotionUpdatesToQueue(queue, withHandler: {
                (deviceMotion: CMDeviceMotion!, error: NSError!) in

                temp_x = acc_x

                acc_x = deviceMotion.userAcceleration.x

                CGContextSetLineWidth(accLine_x, 2)
                CGContextSetStrokeColorWithColor(accLine_x, UIColor.redColor().CGColor)
                CGContextMoveToPoint(accLine_x, i + 10, self.screenHeight * 436 + CGFloat(temp_x * 100))
                CGContextAddLineToPoint(accLine_x, i + 13, self.screenHeight * 436 + CGFloat(acc_x * 100))
                CGContextStrokePath(accLine_x)

                i = (i + 3) % 320
            })

        }
    }   
}
iYoung
  • 3,596
  • 3
  • 32
  • 59
sunyi
  • 3
  • 2

2 Answers2

2

OK, here's some rewritten code... the important point here is that you have to isolate your drawing code from the updates:

var acc_x : Double = 0.0
var temp_x : Double = 0.0
var i: CGFloat = 0

func startMonitoring() {

    motionManager.deviceMotionUpdateInterval = 0.1
    if(motionManager.deviceMotionAvailable) {

        var queue = NSOperationQueue.mainQueue()

        motionManager.startDeviceMotionUpdatesToQueue(queue, withHandler: {
            (deviceMotion: CMDeviceMotion!, error: NSError!) in

            temp_x = acc_x
            acc_x = deviceMotion.userAcceleration.x

            // update things here
            self.setNeedsDisplay()
        })

    }

}

override func drawRect(rect: CGRect) {

    var accLine_x = UIGraphicsGetCurrentContext()

    CGContextSetLineWidth(accLine_x, 2)
    CGContextSetStrokeColorWithColor(accLine_x, UIColor.redColor().CGColor)
    CGContextMoveToPoint(accLine_x, i + 10, self.screenHeight * 436 + CGFloat(temp_x * 100))
    CGContextAddLineToPoint(accLine_x, i + 13, self.screenHeight * 436 + CGFloat(acc_x * 100))
    CGContextStrokePath(accLine_x)

    i = (i + 3) % 320
}   

Please note I did this very quickly but make sure that you call the function "startMonitoring" which should then get the updates from the accelerometer, save a couple of relevant variables (that you were using) and then call setNeedsDisplay. And at some point, drawRect will be called and use the variables that you have saved to correctly draw.

cbiggin
  • 1,942
  • 1
  • 17
  • 18
  • Conceptually, I think this is spot on. `drawRect` should draw a single frame and he should `setNeedsDisplay` elsewhere. I'd be willing to bet he's looking to build on the previous line (so the underlying model would likely be an array of values), but there's certainly enough here for him to figure it out. BTW, I think you might have a strong reference cycle here (like the original had)... – Rob May 30 '15 at 15:44
  • Thank you very much! That is indeed the problem. I have correct my code and it finally works well. Thank you for helping me again! – sunyi May 31 '15 at 09:27
0

The drawRect method is called as a result of you issuing a setNeedsDisplay call. The setNeedsDisplay tell the system that you want to update the drawing and at some point in the future, the system will then call the drawRect method (to do that update).

So if you have a routine that gets called when your underlying data is changed, THEN issue the setNeedsDisplay call.

cbiggin
  • 1,942
  • 1
  • 17
  • 18
  • Could you please write an example code for me? I tried many many times but still can not get a feasible solution. I struggle for several days..... – sunyi May 30 '15 at 14:56