How to invalidate timer while changing tab in tab bar - iphone

When I am moving from one tab to another in the timer continues to run.
But I want to stop that timer.
So if anyone knows then please tell me which method i need to call while moving from one tab to another.

simplest answer is
-(void)viewWillDisappear:(BOOL)animated {
//here
}
when ever you will click on tab, this function will be called and everything written in this function will be executed

You can stop timer process like this,
if(self.TimeOfActiveUser)
{
[self.TimeOfActiveUser invalidate];
self.TimeOfActiveUser = nil;
}
Edit
You can put this method when you pushing another method For Example: if you using Timer for Reload Data of TableView every 6 second then you can push particular row by selecting then you can put this two line of code in
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.TimeOfActiveUser invalidate];
self.TimeOfActiveUser = nil;
objScore = [[CntrScore alloc]initWithNibName:#"CntrScore" bundle:nil];
[self.navigationController pushViewController:objScore animated:YES];
}
AND
if your app Tab based you put timer stop code in viewWillDisappear
-(void)viewWillDisappear:(BOOL)animated
{
if(self.TimeOfActiveUser)
{
[self.TimeOfActiveUser invalidate];
self.TimeOfActiveUser = nil;
}
}

Check the tab bar index and write the code which is given below:
[yourtimername invalidate];

Related

call viewDidDisappear in Tabbar based Application

I am using tab bar based iPhone application.I have set NSTimer in first two tabs.i want to invalidate this timer. so i am invalidating in viewDidDisappear. But when i am clicking on different tab, it will never call viewDidDisappear. I don't know how to call this method?please help me...thanking you in advance...
are you put [super viewWillDisappear:animated]; in viewWillDisappear some time it happaned becouse we forget to put this line in to viewWillDisappear
- (void) viewWillDisappear:(BOOL) animated {
[super viewWillDisappear:animated];
}
set time invalid in viewWillDisappear: method , like bellow..
-(void)viewWillDisappear:(BOOL)animated
{
[yourTimer invalidate];
yourTimer = nil;
}

Loading xib from UIAlertView from a viewcontroller

In my app I have a xib that has several viewcontrollers and xibs (with more viewcontrollers)off of it.
I can go from xib to xib and load what ever view controllers I want.
My problem is when I go to a view in side one off my viewcontrollers (be it on the main xib or another) I have a navigation bar at the bottom with a single button marked "back". Now when this button is hit before it takes you back It asks if you want something to happen.
When you click yes a UIAlertView will pop up and tell you wants about to happen when you click "ok". I know my button is firing by NSLogging my tag.
However I need a certain xib file to load and it does not.
This is the code that I am trying to use -- now this works If I want to go from xib to xib from a button. So I am not sure why its not working in an alert view.
- (void)alertView:(UIAlertView *)alert clickedButtonAtIndex:(NSInteger)buttonIndex {
// the user clicked one of the OK/Cancel buttons
if(alert.tag==1)
{
if (buttonIndex==0) {
ControllPanelViewController *controllpanel = [[ControllPanelViewController alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:controllpanel animated:YES];
NSLog(#"index 0");
}
}
}
Adding pic do to a response:
I have had similar problems before, not with a UIViewController, but with a UIActionSheet. When I tried to do this, I wanted to present a UIActionSheet depending on the selection of the UIAlertView. When I pressed something in the UIAlertView, the view was dismissed, but my action sheet was not shown. This was my solution; instead of:
if(alert.tag==1) {
if (buttonIndex==0) {
ControllPanelViewController *controllpanel = [[ControllPanelViewController alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:controllpanel animated:YES];
NSLog(#"index 0");
}
}
try something like:
if(alert.tag==1)
if (buttonIndex==0)
[self performSelector:#selector(presentController) withObject:nil afterDelay:.1];
with the method presentController being:
ControllPanelViewController *controllpanel = [[ControllPanelViewController alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:controllpanel animated:YES];
NSLog(#"index 0");
The problem seems to be that the UIAlertView takes some time to dismiss itself (very small amount of time) and in that time presenting another view doesn't work.
Also, as Alan Zeino said, if the name of the xib is not the same as the name of the view controller (for example if you have two different xibs- one for ipad and one for iphone), then you do need to specify which to use. If the name of the xib is the same as the view controller, you do not have to specify a name.
Edit:
If you want to use an action sheet and expect the delegate methods to work when their actions are triggered, you'd better set the delegate of the action sheet to self and in your interface file add the protocol.
You need to specify the xib you want to open:
ControllPanelViewController *controllpanel = [[ControllPanelViewController alloc] initWithNibName:#"XibNameHere" bundle:nil];
Since you have indicated that your log statement confirms correctly setting delegate and implementing the methods, the 'UIAlertView locks the screen' theory seems the only expectable one.
As Rickay has said performSelector:AfterDelay: would likely work, but as he has also said that requires a second method to be created. I would say that this is the perfect time for a block.
Here are a couple of options: Either should be copy and paste solutions.
1) Assuming the current main runloop simply has to finish it's current call stack before the new view controller can be pushed you could use:
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
if (alertView.tag == 1) {
if (buttonIndex == 0) {
dispatch_async(dispatch_get_main_queue(), ^{
ControllPanelViewController *controllpanel = [[ControllPanelViewController alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:controllpanel animated:YES];
});
}
}
}
This will add a block to the main queue that will create and show your ControllPanelViewController as soon as the main run loop becomes available.
If, however, that doesn't work and it is 'just a matter of time', a block will still work. Like So:
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
if (alertView.tag == 1) {
if (buttonIndex == 0) {
double delayInSeconds = 0.1;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
ControllPanelViewController *controllpanel = [[ControllPanelViewController alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:controllpanel animated:YES];
});
}
}
}
This will create a block that will 'fire' in the number of seconds specified. Here set to 0.1 seconds.
Again the first one is a cleaner, arguably better, and much easier to read option.

Using MBProgressHUD activity indictor

so I have a table view and whenever user press a row, another class view shows up. So I wanted to have a loading indicator in between the transition. I am using MBProgressHUD, but it showed nothing when I pressed the row. And what should I put inside the #selector()?
[loading showWhileExecuting:#selector() onTarget:self withObject:[NSNumber numberWithInt:i] animated:YES];
Here is my code.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
loading = [[MBProgressHUD alloc] initWithView:self.view];
[self.view addSubview:loading];
loading.delegate = self;
loading.labelText = #"Loading Events, Please Wait..";
[loading showWhileExecuting:#selector(//what should I put) onTarget:self withObject:nil animated:YES];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
if ([[self.citiesArray objectAtIndex:indexPath.row] isEqual:#"NEW YORK"])
{
self.newYorkViewController = [[NewYorkViewController alloc] initWithNibName:#"NewYorkViewController" bundle:nil];
Twangoo_AppAppDelegate *delegate = (Twangoo_AppAppDelegate*)[[UIApplication sharedApplication] delegate];
[delegate.citiesNavController pushViewController:self.newYorkViewController animated:YES];
}
}
You need to implement a waiting function so that when the control returns from that method the HUD will hide/disappear from the screen. So its basically what you do when the HUD is being displayed on the screen, it may be some processing or wait for response for a http request etc. It can also be a timer.
- (void)waitForResponse
{
while (/*Some condition is not met*/)
{
}
}
Also you need to implement the
- (void) hudWasHidden
{
[HUD removeFromSuperview];
[HUD release];
}
You might have a look to the Cocoa documentation chapter on selectors
Selector can be simply see as a pointer to a function.
Then, I guess you are trying to display a progress hud while a particular process is running .. this particular process logically should be isolated in a dedicated method (let's call it doTheJob ).
So start by creating a dedicated method named whatever ( here doTheJob )
- (void) doTheJob;
That being said the MBProgressHUD allows you to simply specify the working method that should be handled by the progress information using the showWhileExecuting method. And the selector is here to defined the target worker method.
[loading showWhileExecuting:#selector(doTheJob) onTarget:self withObject:nil animated:YES];
The target would be the object reference that defines the selector. To remain simple, if you define the method doTheJob in the current class use self as target.
and the withObject, is any parameter that you want / need to provide to the selector method. Beware that if you need to provide parameter to the target method, you need to extend the selector definition with an trailing colon as #selector(doTheJob:)
Hope this helps.

presentModalViewController in viewDidLoad on first launch

I've been searching around but unfortunately have had no luck.
My app requires the user to sign in/sign up the first time he or she launches the app. I know how to determine first launch (using NSUserDefaults) but whenever I try to present the modal containing the sign in/ sign up controls, nothing happens.
Here's what I have:
-(void)viewDidLoad {
[self showLogin];
[super viewDidLoad];
}
-(void)showLogin {
FlipsideViewController *controller = [[FlipsideViewController alloc] initWithNibName:#"AccountView" bundle:nil];
controller.delegate = self;
controller.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:controller animated:YES];
[controller release];
}
However, nothing happens. The main view just loads as normal. Any help is greatly appreciated.
-Giles
[UPDATE]
Fixed simply by using..
-(void)viewDidAppear:(BOOL)animated
{
}
instead of
-(void)viewDidLoad
{
}
Thanks anyway!
/idiocy
I had the same issue and ended up using viewDidAppear as well. The only problem with the viewDidAppear approach is that if you load other UIViewControllers on top, then reshow the base, then your setup code gets called over and over. I ended up having to add a boolean value (initialised to YES) to this view controller and check that value before deciding what to do. Hope this helps someone...
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:(BOOL)animated];
if(justLaunched)
{
justLaunched = NO;
if(settingsFileExists)
{
[self displayMainView];
}
else
{
[self displaySetupView];
}
}
}
How about using performSelector:withObject:afterDelay in the viewDidLoad function? That's how I do it, with a short delay of 0.1s.
And invoking this in the viewDidLoad isn't very safe : the sequence viewDidLoad / viewDidUnload can occur at runtime when the iPhone needs to release some views in order to get back some free memory.
The side effect of such sequence would be that your login controller would be shown...
As you said the viewDidAppear looks better but not simply put it at the end of the appDidFinishedLaunching the delegate of your UIApplication?

What's with [UITableView reloadData]?

I have an application that has a UITableView. This UITableView is populated by an NSMutableArray being held (as a property) in the appDelegate. You can think of this as an email window. It lists messages in a subclassed UITableViewCell. When a new message appears, I have all the code done which downloads the message, adds the data to the appDelegate's NSMutableArray which holds all of the messages. This code is working fine.
Now, once the new message is downloaded and added to the array, I am trying to update my UITableView using the following code, however - the UITableView's delegate functions do not get called.
The odd thing is when I scroll my UITableView up and down, the delegate methods finally get called and my section headers DO change (they show the message count for that section). Shoudn't they update in real-time and not wait for my scrolling to trigger the refresh? Also, the new cell is never added in the section!!
Please Help!!
APPDELEGATE CODE:
[self refreshMessagesDisplay]; //This is a call placed in the msg download method
-(void)refreshMessagesDisplay{
[self performSelectorOnMainThread:#selector(performMessageDisplay) withObject:nil waitUntilDone:NO];
}
-(void)performMessageDisplay{
[myMessagesView refresh];
}
UITableViewController Code:
-(void) refresh{
iPhone_PNPAppDelegate *mainDelegate = (iPhone_PNPAppDelegate *)[[UIApplication sharedApplication] delegate];
//self.messages is copied from appDelegate to get (old and) new messages.
self.messages=mainDelegate.messages;
//Some array manipulation takes place here.
[theTable reloadData];
[theTable setNeedsLayout]; //added out of desperation
[theTable setNeedsDisplay]; //added out of desperation
}
As a sanity check, have you verified that theTable is not nil at that point?
You could try putting a delay on the reloadData call - I had a similar problem when I was trying to get my tableview to update when reordering cells, except that the app crashed if I called reloadData during it.
So something like this might be worth a try:
Refresh method:
- (void)refreshDisplay:(UITableView *)tableView {
[tableView reloadData];
}
and then call it with (say) a 0.5 second delay:
[self performSelector:(#selector(refreshDisplay:)) withObject:(tableView) afterDelay:0.5];
Hope it works...
If you call reloadData from within a dispatched method, make sure to execute it on the main queue.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,0), ^(void) {
// hard work/updating here
// when finished ...
dispatch_async(dispatch_get_main_queue(), ^(void) {
[self.myTableView reloadData];
});
});
..same in method form:
-(void)updateDataInBackground {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,0), ^(void) {
// hard work/updating here
// when finished ...
[self reloadTable];
});
}
-(void)reloadTable {
dispatch_async(dispatch_get_main_queue(), ^(void) {
[myTableView reloadData];
});
}
Have you tried setting a breakpoint in your refresh method just to be sure your messages array has the correct content before calling reloadData?