I am working on Iphone application and new to dev. I am sorry if my question is very basic one. I searched net, but could not get answer.
My question is, when user touches the iphone, I want to get that event to be exexecuted immediately instead of waiting for the previous event to complete.
I call while loop(present in different class) inside touchBegan method. I want to stop that loop when I get another touch event. But touchBegan event is not called (instead queued) as I am still present in the touch began.
Can anybody please help me how to fire the touch event immediately instead of waiting for the previous event to finish.
Thank you in advance.
On the iPhone, one event has to run to completion before the next event is processed. Basically you want to have code which does not run for a long time so that your app remains responsive to user input.
There are a number of way you can handle this.
Put some of the code in a new thread and start that thread from your touchBegan method.
Or turn the loop into multiple events on the main thread. You can do this by calling:
- (void)initializeLoop
{
loopCounter = 0;
[self performSelector:#selector(nextLoop) withObject:nil afterDelay:0.0];
}
- (void)nextLoop
{
loopCounter++;
if (loopCounter<MaxCount)
[self performSelector:#selector(nextLoop) withObject:nil afterDelay:0.0];
}
That way the new touchEnded event can be handled between these other events. Setting the delay higher than 0.0 will make the app even more responsive.
Related
The title says multiple button presses, but actually I'm looking to stack multiple events. I have a chat application that can receive many chat messages at once. In my messageReceived function, I would like to scroll to the bottom of the most recent chats. The problem I'm having is that sometimes many messages (50+) can come in at the same time. I've determined that scrolling to the bottom is a huge performance bottle neck if performed 50 times, but works great if only performed after messages are received.
I'd like scroll to the bottom after a delay, say 0.1 seconds, in my messageReceived function. But I'd like all new chat messages that occur within this 0.1 seconds to "stack", and only issue a single scroll to bottom request.
I think that a system of setting and canceling timers would work for this, however I can't get it right. Is there a better way to make this happen! thanks!
If you are setting your delayed "scroll to the bottom" request with something like
[[self myObject] performSelector:#selector(scrollToBottom:)
withObject:nil
afterDelay:0.1];
then you can use a cancel command like
[NSObject cancelPreviousPerformRequestsWithTarget:[self myObject]
selector:#selector(scrollToBottom:)
object:nil];
then the only time your scrollToBottom: gets called is when it doesn't get cancelled (so, the last time in the bunch). Now you don't need a timer.
Not an exact solution, but something which could guide to right direction. You can set a flag in your .h file and use that to determine if the method has been already called.
In init method set flag as,
self.didCallScrollToBottomMethod = FALSE;
In your scrollToBottomMethod, check the condition as,
if (!self.didCallScrollToBottomMethod) {
self.didCallScrollToBottomMethod = TRUE;
//set the timer here to scroll after 0.1 seconds
}
In the timer method once the scrolling is completed, set the flag as,
self.didCallScrollToBottomMethod = FALSE;
I'm wondering if iOS allows one to do the following:
I have a puzzle game and I've been working on saving data when the user returns to the home screen. To do this, using NSNotificationCenter, I had one of my game classes to observe [UIApplication sharedApplication]'s ApplicationWillResignActive method so when that happens I save my game state. But if the user decides to exit while animations are going on, the game will save a midState where the model values are still changing and that will often cause crashes. My question is if it is possible to somehow delay the saving process (even though it is on the background) until the animations are complete (or some variable equals 1)?
My first idea is to create scheduled event with NSTimer to try to save until everything is set. Any ideas would be appreciated. Thank you
You can use performSelector:withObject:afterDelay:
// Call doSomething after a 1 second delay
[self performSelector:#selector(doSomething) withObject:nil afterDelay:1.0f];
Rather than trying to delay the saving, especially in ApplicationWillResignActive, you should look into how to stop the animation and record the expected final values of the animation. Depending on the method of animation (UIView static methods, block based, 3rd party) there is usually a way to stop them, and since you define what the animation does you should already know the final state.
In the case of block based animations:
How to cancel UIViews block-based animation?
In my iPhone app I want to logout the user if nothing happens till about 2 minutes (e.g. the user puts down the phone). Does anybody has such issue? What is the best way to implement this feature? I think I save the date of last event to NSUserDefaults, then on the next event first I check the current date. If the difference is larger than 2 minutes go to login screen, else refresh the stored date. But how can I get the touch event generally?
Thanks, madik
There's a method in UIApplicationDelegate for that:
- (void)applicationWillResignActive:(UIApplication *)application
{
/*
Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
*/
}
Note that it also will be called when the app is going to background state. That will help you store the data whenever the app is going to inactive state. If you want to check if a certain amount of time has passed, you will have to use a NSTimer and store the last touch event. I think it cannot be done because you can't intercept all the touch events (Maybe it's over an object managed by the system. The status bar is an example). I guess is better to let the system to manage all the activity/inactivity stuff and store your data when necessary.
EDIT: I didn't understand what you mean the first time. Check this accepted answer, it accomplish what you need. Basically you have to subclass UIApplication and override sendEvent method.
'NSTimer'
When you say "how can I get the touch event generally?", if you mean how can you tell if the user is idle or not, you'll have to set up some system to gather all touch events at a higher level in your app. You could update the last touch time you mentioned in NSUserDefaults but that may be inefficient during the run of the app, so you could just post the touch event to your main app delegate and have it save the time of last touch. Which would also be where you could set up the 2 minute timer.
Something like:
- (void) someAppDelegateMethodThatYouCallForAnyUserEvent
{
[self.idleTimer invalidate];
self.lastEvent = [NSDate now];
self.idleTimer = [NSTimer scheduledTimerWithTimeInterval:120 target:self selector:#selector(logoutAndGotoLogin) userInfo:nil repeats:NO];
...
}
You'll also have to do some cleanup in your app delegate methods when the app goes to background etc if you support that behavior.
My application has a button when clicked it is disabled, an activity indicator displayed and a background task is executed. When this task is completed a callback updates the interface by enabling the button and removing the activity indicator. The problem I having is the task is completing the callback function is executed but for a period of time the activity monitor remains on the screen, the button looks like it is disabled but it is possible to click it again. Can anyone tell me where I am going wrong?
Thanks very much!
Could it be that the callback-method is being executed in a separate thread?
I'm asking, because any calls that have impact on a view should be performed on the main thread.
The problem might be solved by doing the following:
create a Method that handles your UI-related code and gets called within your callback method
the UI-related code has to be performed on the main thread
It could look a little bit like this:
//gets called asynchronously when your operation has completed
-(void)myCallbackHandler {
[self performSelectorOnMainThread:#selector(updateUI) withObject:nil
waitUntilDone:NO];
}
-(void)updateUI {
[myActivityIndicatorView stopAnimating];
[myButton setEnabled:YES];
}
I've implemented a tap-and-hold handler using an NSTimer that I first set in the TouchesBegan overload.
However, what I actually want is for an action to be continuously performed in quick-fire succession while the touch is being held. So, on timer expiry I call a handler to do the work, which then sets another timer and the cycle continues until the TouchesEnded comes in and cancels it, or another terminating condition is met.
This works fine, until my handler code triggers an animation to go off at the same time.
Now we have animation events and timer events going off, and in all that we need to handle TouchesEnded as well.
What I am finding is that, if the animation is triggered, and I set my timer to less than 0.025 seconds, my TouchesEnded event doesn't come through until the timer cycle stops (the other terminating condition). Setting a slower timer, or not triggering the animation, make it work (TouchedEnded comes in straight away), but are not what I want.
Obviously this is all on the device (release build - no NSLogs) - in the sim it all works fine
Is there any way of setting the relative priorty of these events - or is it likely I'm missing something else obvious here?
[Update]
I've worked around this in this instance by doing the continuous part without visual feedback until it's done (which from this users perspective is instant). I think this is ok for now. I'd still like to hear any more thoughts on this (Jeffrey's idea was good), but I'm not waiting on tenterhooks now.
Try writing your own Timer-type class by spawning off onto a thread. Example:
BOOL continue = YES; //outside of your #implementation
-(void)doLoop
{
while(continue){
[NSThread sleepForTimeInterval:.025];
[self performSelectorOnMainThread:#selector(whateverTheFunctionIs) waitUntilDone:YES];
}
}
and this would be started by [NSThread detatchNewThreadSelector:#selector(doLoop) toTarget:self withObject:nil]. This is not exactly threadsafe, but you can choose to wrap the boolean into a NSNumber and then do #synchronize on it if you so choose. Alternatively, after I wrote that little snippet I realized it would be better to do a check against the current NSTime instead of sleepForTimeInterval: but you get the point. :)