-2

I am wantintg to experement on some sample code from an online tutorial which runs fine before I add my func to it. I am wanting to add UIDynamics and apply gravity to the series of points on a line in the chart/graph and just make it fall off screen, but I seem to be missing something? It is crashing with [__NSCFNumber center] unrecognized selector sent to instance if anyone can tell me why I would love it.

online sample is from Ray Wenderlich's site and was written by Caroline Begbie for a tutorial. It works great. The only func I added however is crashing it.

    import UIKit  
@IBDesignable class GraphView: UIView {  



  var graphPoints:[Int] = [4, 2, 6, 4, 5, 8, 3]  


  @IBInspectable var startColor: UIColor = UIColor.redColor()  
  @IBInspectable var endColor: UIColor = UIColor.greenColor()  

  override func drawRect(rect: CGRect) {  

    let width = rect.width  
    let height = rect.height  


    var path = UIBezierPath(roundedRect: rect,  
      byRoundingCorners: UIRectCorner.AllCorners,  
      cornerRadii: CGSize(width: 8.0, height: 8.0))  
    path.addClip()  


    let context = UIGraphicsGetCurrentContext()  
    let colors = [startColor.CGColor, endColor.CGColor]  


    let colorSpace = CGColorSpaceCreateDeviceRGB()  


    let colorLocations:[CGFloat] = [0.0, 1.0]  


    let gradient = CGGradientCreateWithColors(colorSpace,  
      colors,  
      colorLocations)  


    var startPoint = CGPoint.zeroPoint  
    var endPoint = CGPoint(x:0, y:self.bounds.height)  
    CGContextDrawLinearGradient(context,  
      gradient,  
      startPoint,  
      endPoint,  
      0)  



    let margin:CGFloat = 20.0  
    var columnXPoint = { (column:Int) -> CGFloat in  
      /  
      let spacer = (width - margin*2 - 4) /  
        CGFloat((self.graphPoints.count - 1))  
      var x:CGFloat = CGFloat(column) * spacer  
      x += margin + 2  
      return x  
    }  



    let topBorder:CGFloat = 60  
    let bottomBorder:CGFloat = 50  
    let graphHeight = height - topBorder - bottomBorder  
    let maxValue = maxElement(graphPoints)  
    var columnYPoint = { (graphPoint:Int) -> CGFloat in  
      var y:CGFloat = CGFloat(graphPoint) /  
        CGFloat(maxValue) * graphHeight  
      y = graphHeight + topBorder - y /  
      return y  
    }  



    UIColor.whiteColor().setFill()  
    UIColor.whiteColor().setStroke()  


    var graphPath = UIBezierPath()  

    graphPath.moveToPoint(CGPoint(x:columnXPoint(0),  
      y:columnYPoint(graphPoints[0])))  



    for i in 1..<graphPoints.count {  
      let nextPoint = CGPoint(x:columnXPoint(i),  
        y:columnYPoint(graphPoints[i]))  
      graphPath.addLineToPoint(nextPoint)  
    }  




    CGContextSaveGState(context)  


    var clippingPath = graphPath.copy() as! UIBezierPath  


    clippingPath.addLineToPoint(CGPoint(  
      x: columnXPoint(graphPoints.count - 1),  
      y:height))  
    clippingPath.addLineToPoint(CGPoint(  
      x:columnXPoint(0),  
      y:height))  
    clippingPath.closePath()  


    clippingPath.addClip()  

    let highestYPoint = columnYPoint(maxValue)  
    startPoint = CGPoint(x:margin, y: highestYPoint)  
    endPoint = CGPoint(x:margin, y:self.bounds.height)  

    CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0)  
    CGContextRestoreGState(context)  


    graphPath.lineWidth = 2.0  
    graphPath.stroke()  


    for i in 0..<graphPoints.count {  
      var point = CGPoint(x:columnXPoint(i), y:columnYPoint(graphPoints[i]))  
      point.x -= 5.0/2  
      point.y -= 5.0/2  

      let circle = UIBezierPath(ovalInRect:  
        CGRect(origin: point,  
          size: CGSize(width: 5.0, height: 5.0)))  
      circle.fill()  
    }  




     var linePath = UIBezierPath()  


    linePath.moveToPoint(CGPoint(x:margin, y: topBorder))  
    linePath.addLineToPoint(CGPoint(x: width - margin,  
      y:topBorder))  


    linePath.moveToPoint(CGPoint(x:margin,  
      y: graphHeight/2 + topBorder))  
    linePath.addLineToPoint(CGPoint(x:width - margin,  
      y:graphHeight/2 + topBorder))  


    linePath.moveToPoint(CGPoint(x:margin,  
      y:height - bottomBorder))  
    linePath.addLineToPoint(CGPoint(x:width - margin,  
      y:height - bottomBorder))  
    let color = UIColor(white: 1.0, alpha: 0.3)  
    color.setStroke()  

    linePath.lineWidth = 1.0  
    linePath.stroke()  

    createFallAnimation() // my only func I added to the project  
  }  


   // My new code added to the project that is crashing it.  
    func createFallAnimation() {  

        var animator:UIDynamicAnimator? = nil  
        animator = UIDynamicAnimator(referenceView:self )  


        let gravity = UIGravityBehavior(items: graphPoints)  
        gravity.gravityDirection = CGVectorMake(0.0, 0.5)  

        animator?.addBehavior(gravity)  

    }  
}  

Here is the crash log:

2015-07-24 08:52:48.092 Flo[51164:11291157] -[__NSCFNumber center]: unrecognized selector sent to instance 0xb000000000000043
2015-07-24 08:52:48.097 Flo[51164:11291157] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFNumber center]: unrecognized selector sent to instance 0xb000000000000043'
*** First throw call stack:
(
  0   CoreFoundation                      0x000000010d55cc65 __exceptionPreprocess + 165
  1   libobjc.A.dylib                     0x000000010f309bb7 objc_exception_throw + 45
  2   CoreFoundation                      0x000000010d5640ad -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
  3   CoreFoundation                      0x000000010d4ba13c ___forwarding___ + 988
  4   CoreFoundation                      0x000000010d4b9cd8 _CF_forwarding_prep_0 + 120
  5   UIKit                               0x000000010e7b7f11 -[UIDynamicAnimator _registerBodyForItem:shape:] + 672
  6   UIKit                               0x000000010e7bc006 -[UIGravityBehavior _addItem:] + 43
  7   UIKit                               0x000000010e7bc6b5 -[UIGravityBehavior _associate] + 293
  8   UIKit                               0x000000010e7b5b97 -[UIDynamicAnimator _registerBehavior:] + 244
  9   Flo                                 0x000000010d3318db _TFC3Flo9GraphView20createAnimationStufffS0_FT_T_ + 331
  10  Flo                                 0x000000010d33166b _TFC3Flo9GraphView8drawRectfS0_FVSC6CGRectT_ + 6555
  11  Flo                                 0x000000010d33177d _TToFC3Flo9GraphView8drawRectfS0_FVSC6CGRectT_ + 93
  12  UIKit                               0x000000010e0bd5d2 -[UIView(CALayerDelegate) drawLayer:inContext:] + 495
  13  QuartzCore                          0x0000000112930a2a -[CALayer drawInContext:] + 119
  14  QuartzCore                          0x000000011282a92b CABackingStoreUpdate_ + 2793
  15  QuartzCore                          0x0000000112930933 ___ZN2CA5Layer8display_Ev_block_invoke + 59
  16  QuartzCore                          0x00000001129307be _ZN2CA5Layer8display_Ev + 1478
  17  QuartzCore                          0x00000001129254d9 _ZN2CA5Layer17display_if_neededEPNS_11TransactionE + 301
  18  QuartzCore                          0x0000000112925561 _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 35
  19  QuartzCore                          0x000000011289186e _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 242
  20  QuartzCore                          0x0000000112892a22 _ZN2CA11Transaction6commitEv + 462
  21  UIKit                               0x000000010e03b9ed -[UIApplication _reportMainSceneUpdateFinished:] + 44
  22  UIKit                               0x000000010e03c6b1 -[UIApplication _runWithMainScene:transitionContext:completion:] + 2648
  23  UIKit                               0x000000010e03b095 -[UIApplication workspaceDidEndTransaction:] + 179
  24  FrontBoardServices                  0x0000000111aed5e5 __31-[FBSSerialQueue performAsync:]_block_invoke_2 + 21
  25  CoreFoundation                      0x000000010d49041c __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 12
  26  CoreFoundation                      0x000000010d486165 __CFRunLoopDoBlocks + 341
  27  CoreFoundation                      0x000000010d485f25 __CFRunLoopRun + 2389
  28  CoreFoundation                      0x000000010d485366 CFRunLoopRunSpecific + 470
  29  UIKit                               0x000000010e03ab02 -[UIApplication _run] + 413
  30  UIKit                               0x000000010e03d8c0 UIApplicationMain + 1282
  31  Flo                                 0x000000010d3432f7 main + 135
  32  libdyld.dylib                       0x000000010fa3f145 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

I have a feeling I can't use array elements that are intergers? I think they need to be objects? Any help would be great. If you want to mess with the entire project yourself it can be found on Ray Wenderlich under Core Graphics and Swift part 2.

auth private
  • 1,318
  • 1
  • 9
  • 22
Robert
  • 63
  • 7

1 Answers1

0

This is incorrect, and it's unclear what you wanted to happen:

var graphPoints:[Int] = [4, 2, 6, 4, 5, 8, 3]  
...
let gravity = UIGravityBehavior(items: graphPoints)  

This says "please attach gravity behavior to several integers." How would integers respond to gravity?

Behaviors can only be applied to things that conform to UIDynamicItem (things that have bounds, center, and transform). Integers don't have any of those, and it's unclear how they even could.

What you're trying to do (animate a graph) is quite a bit more complicated. When you move the points, you would then need to redraw the path based on the new points. To animate that, you'd need to use something that can animate paths (likely a CAShapeLayer which does it well). That's going to be completely different code than this sample.

Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • I see your point. I am wanted to make the line (a UIBezierPath) drop off the chart. I have seen charts use animation to draw that path using Core Animation but in theory UIDynamics should be able to do the same thing. – Robert Jul 24 '15 at 14:51
  • Pretty easily, but there's no reason to animate the path itself. Just animate the entire view it's in. If it's mixed with other things, make the part you want to animate separate and put it in its own view or layer. Creating views out of many separate CALayers is very common iOS practice. – Rob Napier Jul 24 '15 at 14:52
  • I totally get what you are saying. Way easy actually. I routinely have this mind set problem of losing the forest for the trees when I come up with an idea I want to try out. Thanks again. – Robert Jul 24 '15 at 15:06