I'd like to do several things in my app after the user has touched - the longer they touch, the better - is there a limit? Will iOS 'force' a touchesEnded after too long?
There's likely no limit. The constraint it probably more a user experience one (at what point might a long press become annoying).
touchesEnded will be called when touch(es) end. You can (theoretically) take as much time as you want in touchesBegan handler. But that can (and probably will) result in bad UI responsiveness.
If you really need to do something that takes a lot of time you might want to consider starting a background thread in touchesBegan.
If memory serves me right touchesMoved will only be called when touchesBegan method reaches the end - touches will be buffered though.
EDIT: as for your updated question: no, there is no limit to this besides the battery and users patience. Depends on what you want to achieve there might be a more elegant solution than staying in touchesBegan.
Related
I am building a simple ios gaming app where I have to move a few objects on screen, and these moving objects react to swipe gestures and change their direction based on that. I am not using spritekit or any other gaming framework for this, and the way I am moving the objects is by triggering an NSTimer that fires 60 times a second. I am not using any threads explicitly so I guess the timer is executed by the main thread ? The code block that the timer triggers updates the location of objects based on their speed (defined as pixels per time unit in x/y direction). It is working fine and I am almost at the end of my project, but while testing the app I've realized that although the movement of objects seem pretty good most of the times, however sometimes the movement is a little rough/patchy.
My question is that is it the right way to do something like this, how can I improve the performance ? will using something like GCD can help with the issue of jittery movement ? (I haven't looked into GCD in detail but I am willing to spend time on it if I know that will help)
Thanks for any help !
and the way I am moving the objects is by triggering an NSTimer that fires 60 times a second
I would recommend not doing that. Various forms of animation are built in (View animation, Layer animation, CADisplayLink, UIKit Dynamics), and of course there's always Sprite Kit. Use the tools you are given for this purpose. Don't reinvent the unicycle when you already have a Ducati at your disposal.
3D touch seems really cool and I wanted to see how it would work in a musical context. I was reading a bit about 3D touch and it seems like the force property almost always reads as 0 when a touch begins (touchesBegan method).
How do I get a usable force when a touch begins because even if I'm pressing with maximum "force" I'm still getting that initial 0? I was thinking about just approximating a value within a time frame but that would involve me moving the touch. I just want a usable force upon the first touch.
Thanks!
Unfortunately this is impossible.
Every touch starts as a contact with no force at all, as soon as the user's finger makes contact (or even near-contact) with the screen. The force only starts to build as the user's finger is compressed against the screen.
The only way for touchesBegan: to report any force at all would be for it to delay artificially for a certain number of milliseconds before reporting a touch, to allow the force to build up. This would destroy the interactivity of all iOS applications; and Apple put a huge amount of work into delivering a touch the instant it is detected.
On Mac, one can always get the location of the mouse "outside the event stream" (ie, even if you've not subscribed to any delegate methods for mouseUp: et al) by calling [NSEvent mouseLocation].
Is there any way on iOS to get current touch events without listening to touchesBegan:?
I ask because there is at least one situation in which touchesBegan is not called: at app launch, if a touch is already in progress, touchesBegan is never called. In fact, neither are any of the touch-related UIEvent methods called as near as I can tell (nor UIApplication's / UIWindow's sendEvent:, apparently).
I would like to vary the behavior of my app slightly based on whether a touch is in progress at launch. Is there any way to detect an in-progress touch at app launch?
This cannot be done. The simple reason: The touch events don't belong to your app. Each touch belongs to some UI element (or responder). As you already know, this element gets the began, moved, ended, cancelled messages.
This is even true within a properly programmed app: All events regarding one touch are delivered to the very same object. After all, how would another object know what to do with that event, and how should the first object properly finish its expected behavior?
While you can (or could, but probably shouldn't) find a work around within your app, there's just no way for cross-app-touch passings.
And on the Mac you may query the mouse position, but in normal application flow there'll always be a mouse down before you get a mouse up event.
To be honest, I don't see any reason why this would be needed anyway... oh wait... I could split my app icon into several areas... not sure if it would already break privacy laws, though, if you get to know where the user has his icon on screen.
I think you could simply "extend" the application launch. When I had time consuming tasks during my application launch, I used to show the same splash screen with a UIActivityIndicator while the action was being carried out.
You could simply create a NSTimer, wait for about 2 seconds and during this time, check for touches, while the splash screen will still be showing.
To do this, in applicationDidFinishLaunch, push a ViewController that looks exactaly like the splash screen and check for touches in this ViewController. After those 2 seconds, proceed with normal initialisation. This behaviour also helps if you have time consuming tasks during initialisation.
I know, it`s a workaround, but my guess, is that it is not possible to check for touches because application will be working on the main thread and the touches also processes on the main thread. This could happen also because there are no ViewControllers or UIWindow initialised and ready to listen to touches.
Hope it helps.
You might try handling the hitTest:withEvent: instead.
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;
Since according to apple doc "Returns the farthest descendant of the receiver in the view hierarchy (including itself) that contains a specified point."
I'm working on a game, and I'm using a CAEAGLLayer backed UIView subclass to present the game engine. Touch handling is done using -touchesBegan:withEvent: et. al.
Everything works fine, except that very rarely, if one of the on-screen controls is tapped rapidly, -touchesBegan:withEvent: doesn't get called for somewhere between 0.1 and 1-2 seconds. This happens maybe one in 20 times, and only if you tap the screen rapidly (4-5 times) first. It seems to be more likely to happen if I am also holding down another finger on a different control on the screen.
Thinking that it was something to do with my own code, I subclassed UIApplication so I could add a logging statement to -sendEvent:. When the laggy touch happens, -sendEvent: doesn't get called until some period of time after the touch has started, so it the touch handling code inside my UIView subclass doesn't appear to be at fault.
Does anyone have any idea what's going on here (other than iOS having some obscure bug)? Is there some sort of internal "events queue" that makes event delivery become laggy when it fills up? Has anyone else experienced this?
Touch events are only dispatched in the main UI run loop, and sometimes only when the main run loop goes idle for a bit. So if your app is busy handling several previous touch events in a row without taking a break, the main UI run loop might be saturated, and thus not get any further touch events until done with the current stuff.
Touch events also have time stamps. So you can check if they're coming too fast (faster than your event handlers and resulting UI updates can run), and skip or combine some of the event handlers, as appropriate for your app, if you want the app to stay maximally responsive.
I am developing a tic tac toe game for iOS and I am using a combination of UIButtons and UIImageViews to allow for user interaction and to display the moves made. My problem is that the buttons continue to accept user input before the cpu makes it's move, which breaks my game logic. I have made several attempts to toggle the userInteractionEnabled property, but I have only been able to turn it off. The engine that gets everything started in the game is my buttonPressed method. I also toggle the userInteractionEnabled property within this method and therein lies my problem: How do I re-enable the property after disabling user interaction? Is there a method that is called in between events that I can overwrite?
I have searched the web and I have searched through the developer documentation provided by Apple and I found information on the touchesBegan and touchesEnded methods. However, from what I understand, those methods need to be explicitly called which brings me back to my original problem of not being able to call those functions without the user's interaction.
If anyone can help, I would greatly appreciate it! I have been racking my brain over this for the past couple of weeks and I am just not seeing a solution.
I'd think that for a game like tic-tac-toe, calculating the countermove should be so fast that it can be done immediately in response to the first button press. If you're doing something complicated to calculate the next move, like kicking off a thread, you might want to reconsider that.
Let's say, though, that your game is something like chess or go, where coming up with a countermove might take a bit longer. Your view controller should have a method to make a move for the current player, let's call it -makeMove:. Your -buttonPressed action should call that method to make a move for the user. In response, -makeMove: should update the state of the game, switch the current player to the next player. If the new current player is the computer, it should then disable the controls and start the process of calculating the next move. Let's imagine that's done by invoking some NSOperation, so that coming up with the next move is an asynchronous task. Once the operation has come up with a move, it should again invoke -makeMove: (by calling -performSelectorOnMainThread:), which will again update the game state and the current player. This time, though, it should see that the new current player is not the computer, and so it should re-enable the controls.