Search code examples
swiftcoordinatesnstimer

Get object x/y coordinates + NSTimer crash for unknown reason


  1. Is there a command to get an object's x/y coordinates? Also, is there anyway to get the coordinates of the center of the screen?

  2. I'm trying use an NSTimer to add a CircleView every second, but it's crashing unexpectedly.

    var timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector(view.addSubview(circleView)), userInfo: nil, repeats: true)
    

    This is the circleView passed to Selector(view.addSubview(circleView)):

    var circleWidth = CGFloat(200)
    var circleHeight = circleWidth
    // Create a new CircleView
    var circleView = CircleView(frame: CGRectMake(200, 0, circleWidth, circleHeight))
    

    It's crashing with:

    Theard 1 : EXC_BAD_ACCESS (CODE=1,ADDRESS=0X0).
    

Solution

  • First, yes, you can get the x/y position of any UIView easily; it's also easy to get the coordinates of the center of the screen.

    A UIView's position (in the coordinate system of its superview) is here:

    view.frame.origin
    

    Note: The origin is the top-left corner of the UIView.

    The center of the screen can be determined like this:

    let screenBounds = UIScreen.mainScreen().bounds
    let centerOfScreen = CGPoint(x: CGRectGetMidX(screenBounds), y: CGRectGetMidY(screenBounds))
    

    You probably want the center of the UIView you're adding your new view to though, that's pretty much the same, just replace UIScreen.mainScreen().bounds with view.bounds (where view is the UIView you're adding your new view to).

    Second, you're timer is crashing because you're giving it an invalid Selector. You can't create a Selector by passing it a function directly, you need to pass it a String containing the name of the function you want it to point to. When you do this:

    Selector(view.addSubview(circleView))
    

    You're actually calling view.addSubview(circleView) immediately and passing the value it returns to Selector. Since addSubview returns Void, you're essentially creating a Selector pointing to nil, which is invalid. When your NSTimer fires, it tries to call that nil Selector and crashes.

    The correct way to do what your code is attempting is to create a new function that adds your CircleView and pass the name of that function to Selector:

    func addCircleView() {
        var circleWidth = CGFloat(200)
        var circleHeight = circleWidth
        // Create a new CircleView
        var circleView = CircleView(frame: CGRectMake(200, 0, circleWidth, circleHeight))
        view.addSubview(circleView)
    }
    

    And then setup your NSTimer like so:

    var timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("addCircleView"), userInfo: nil, repeats: true)
    

    Note: You don't actually need to put Selector around "addCircleView", Swift will figure out that you need a Selector there and convert a string literal to it automatically.