0

I created a UIView component (in main storyboard it occupies the whole screen). The class it linked to is called MyFullView which looks like this:

import UIKit

    class MyFullView: UIView {
        var myTouch: UITouch?

        override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
            super.touchesBegan(touches, with: event)
            // I only initialized myTouch here.
            myTouch = UITouch()
            myTouch = touches.first
        }

        override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
             // I just print out myTouch location, magically the value is updated for each finger movement, why?
             print("myTouch = \(myTouch?.location(in: self))")
             super.touchesMoved(touches, with: event)
       }
    }

I declared the variable myTouch & initialized it in touchesBegan callback. I don't have any code update the value of myTouch.

But when I run my app in emulator, mouse click & move/drag, I can see the log .e.g.:

myTouch = Optional((100.5, 117.0))
myTouch = Optional((99.5, 117.0))
myTouch = Optional((99.0, 117.0))
myTouch = Optional((98.5, 117.0))
myTouch = Optional((98.5, 118.0))
myTouch = Optional((98.0, 118.0))
myTouch = Optional((97.5, 118.0))
...

Why & How the hell does myTouch variable update the value of itself? I don't understand, could someone please explain to me what is the magic?

Leem.fin
  • 40,781
  • 83
  • 202
  • 354

2 Answers2

0

Your answer lies in the second line here:

        myTouch = UITouch()
        myTouch = touches.first

You have assigned myTouch to the first object in touches. When you get touch events, it happens that the UITouch will be the same instance for the lifecycle of the touch (until you get a finished or cancelled).

So you're seeing the positional updates of the touch in touchesMoved.

If you want to have the original location, you will need to store it then.

Note your code will have issues with multi touch.

Mobile Ben
  • 7,121
  • 1
  • 27
  • 43
  • Thanks, are you saying the `touches` passed in `touchesBegan(...)` & `touchesMoved(...)` refer to the same `touches: Set` instance? – Leem.fin Nov 06 '16 at 21:14
  • Yes. This is so you know it is the same touch. During multi-touch, your `touchesBegin` could actually have more than one `UITouch` in `touches`. Likewise, with multi-touch, your `touchesMoved` could also have more than one. Since the instances are the same, you have a means to keep track of them. This is necessary to track gestures as well as correlating touch up/down events, etc. – Mobile Ben Nov 06 '16 at 21:17
  • I still don't understand, let's only talk about single finger gesture. Even though it is the same instance of `touches: Set` in different callbacks, the `touchBegan(...)` callback is only called once (when first touch on the screen), at that point, I assign the first touch to `myTouch` by `myTouch=touches.first`, then, I move my finger, the `touches.first` is changed to a new UITouch value, but I didn't assign the new value to `myTouch`, how can myTouch knows the new value? – Leem.fin Nov 06 '16 at 21:24
  • It's the same instance (which is why i responded Yes). Print out the pointer value and you will see. Single touch or multi-touch doesn't change this. I only referenced multi-touch because in theory it is a better illustration of it. I know you're not talking about multi-touch events but read this: https://developer.apple.com/library/content/documentation/EventHandling/Conceptual/EventHandlingiPhoneOS/multitouch_background/multitouch_background.html in section "Handling a Complex Multitouch Sequence" they discuss using UITouch as a key (since it is the same) – Mobile Ben Nov 06 '16 at 21:33
  • The linked pages says "... using the addresses of the UITouch objects as keys", so each UITouch object inside `touches: Set` has a address & using that as key. But it doesn't explain my question still. For example, in `touchesBegan(...)` callback, the `touches` set contains position (100,100) only, `myTouch` would also have this location, then, finger moved, `touchesMoved(...)` is triggered, let's say now the set of touches positions are {(100,100), (102,102)}, how does `myTouch` points to the UITouch that has location (102,102) ? That's is the thing confused me. – Leem.fin Nov 06 '16 at 21:50
  • It is the same instance. When the position changes, the position in the UITouch changes ... because is the same instance. In your example it is 100, 100 when it begins. When it moves, the same instance of UITouch is given in touchesMoved, however the position is updated to 102, 102. Did you even print out the address like I suggested? Note the relevant point of that section is showing of an example of how one would save the initial position. This is because the value of position in the UITouch reflects he current position value. – Mobile Ben Nov 06 '16 at 21:55
  • Can I understand your words to following one "When the position changes, the position in the UITouch of `touches.first` retrieved from `touchesBegan` changes & `myTouch` points to the same instance of that UITouch all the time"? & if so, print out the address of which instance to illustrate this? – Leem.fin Nov 06 '16 at 22:04
  • Only you can know if this will work in illustrating it. You keep asking the question if it is the same instance, and the answer is yes. The same instance here is represented by the same physical address of the object. At this point, I'm just repeating the same statement and I unfortunately am not certain how to present it in a way that you can understand otherwise. It is the same instance which is why in this case the position is different. it is the way Apple implemented it. – Mobile Ben Nov 06 '16 at 22:08
  • AHA!!!Now I see why it is hard for me to understand, because I misunderstood the meaning of UITouch, I thought each UITouch represents one location of a time when finger moves, but actually, each UITouch represents each finger, if there is only one finger touches the screen, the `touches: Set` always has one UITouch, if multi-finger touch, the set contains a set of UITouchs with each UITouch trackes one finger's location. Is that right? if so, then it makes sense with all your words to me. – Leem.fin Nov 06 '16 at 22:10
  • Yes, that is why you get an NSSet. And why it is okay to use them as the key in the CFDictionaryRef – Mobile Ben Nov 06 '16 at 22:15
  • Thanks for your patient! – Leem.fin Nov 06 '16 at 22:20
0

UITouch is a class, which means that when you set a variable to be a UITouch, you are making a reference to the other UITouch, rather than making a new UITouch. If this is an issue for you, I would store the touch as a CGPoint (which is a struct). Alex Wayne's answer described this difference between classes and structs very well.

Community
  • 1
  • 1
C1FR1
  • 133
  • 1
  • 9
  • I know the difference between class and struct. No need to discuss that. Let's only consider single finger gesture. I assign the `touches.first` to `myTouch` in `touchesBegan(...)` callback, which means I make a reference to `touches.first` at that point to `myTouch`. When finger moves, `touchesMove(...)` callback is triggered, there, the `touches.first` points to a new `UITouch` value, right? So, are you saying `touches.first` in `touchesBegan(...)` and that in `touchesMove(...)` refers to the same `UITouch`???? I don't quite get what do you mean. – Leem.fin Nov 06 '16 at 21:32
  • To my understanding (which may not be the best since I don't use these functions often) there is an array of UITouches stored somewhere in memory. When one of those functions is called, that array is the touches parameter. When you set myTouch to be the first item in the array, myTouch then references the first item in the array. TouchesMoved() seems to be called when that array is changed. I don't know if this is true, but it makes the most sense given this interaction. – C1FR1 Nov 07 '16 at 03:14