I have a recursive call to perform some logged movements from user. While the animation is performed using the following recursive call, if user presses the back button to pop the viewcontroller out of the stack, somehow the animation doesn't stop and I can see the log entries (representing different log movements) on the console.
-(void)replayNextLog {
if ((replayLogIndex < [lastTurnGameLogList count]-1) && (!skipReplayButtonWasPressed)) {
float delayToNextReplay;
//the replayLogIndex ends with count-1 because the last one is empty due to the last empty line
NSDictionary *logEntryDict = [lastTurnGameLogList objectAtIndex:replayLogIndex];
for (id key in logEntryDict) {
if ([key isEqualToString:kGuessMoveTypeLetterButton]) {
} else if ([key isEqualToString:kGuessMoveTypeRevealHint]) {
} else if ([key isEqualToString:kGuessMoveTypeReset]) {
} else if ([key isEqualToString:kGuessMoveTypePass]) {
} else if ([key isEqualToString:kGuessMoveTypeShuffle]) {
}
}
replayLogIndex++;
// Recursive call
[self performSelector:#selector(replayNextLog) withObject:nil afterDelay:delayToNextReplay];
}
}
Could it be because of any leaks in the view controller? For your convenience, let me tell you that I am not reaching the dealloc method of the VC.
Thanks in advance.
Regards,
Obaid
You will need to control the animation/recursion, possibly using an instance variable, and start it from within the viewDidAppear method and stop it from the viewDidDisappear method. The view controller isn't necessarily destroyed just because it's popped from the navigation controller.
Related
I'm trying to add a custom UIActivity to a UIActivityController. When I click on the item, it presents the view controller I want it to, but when I finish with that view controller, the original UIActivityViewController is still there. My question is, how and where do I dismiss the activity view controller? This is the code in my custom UIActivity.
- (BOOL)canPerformWithActivityItems:(NSArray *)activityItems{
self.activityTitle = #"Text Editor";
self.activityType = #"TextEdit";
self.activityImage = [UIImage imageNamed:#"Icon.png"];
if (activityItems) return YES;
else return NO;
}
- (void)prepareWithActivityItems:(NSArray *)activityItems{
for (NSString *path in activityItems) {
if ([path lastPathComponent]) {
self.file = path;
}
}
}
- (UIViewController *)activityViewController{
ACTextEditController *actec = [[ACTextEditController alloc] initWithFile:_file];
return actec;
}
EDIT
I've tried doing this, and I know it is called because I tried logging something in it and it was called
- (void)activityDidFinish:(BOOL)completed{
if (completed) {
[self.activityViewController dismissViewControllerAnimated:YES completion:nil];
}
}
however, it's still there when the view controller dismisses. Why?
Here's a working example:
http://www.apeth.com/iOSBook/ch26.html#_activity_view
Notice that we end up by calling activityDidFinish:. That is what tears down the original interface. It may be that that is the step you are omitting. If not, just compare what you're doing with what I'm doing, since what I'm doing works (on iPhone).
I have created a keyboard with some arrow keys that allows the user to navigate with arrow buttons, between all the text fields in the tableview. (2 per cell)
There are some situations where cells will be disabled, so I have a recursive call to skip them. ie. if the user presses the right arrow, and the textField is disabled, recursively call the right arrow again to skip it.
I also animate any scrolling that needs to be done myself. However, something has happened recently that is causing a EXEC_BAD_ACCESS when trying to set the firstResponder after a user navigates to a new textField, and the scrolling animation is finished.
I am able to reproduce this issue starting in the first cell and navigating down 2 times. Here is the code, in order of what is happening as best as I can display it, with a lot edited (like all the code for the other 3 arrow buttons so u only see the lines called)
//receive the arrow button pressed first
_arrowButton = arrowButton;
#try
{
switch (_arrowButton.tag)
{
case NumericKeyboardViewDownArrow:
destinationIndexPath = [NSIndexPath indexPathForRow:currentIndexPath.row + 1 inSection:currentIndexPath.section];
newTag = currentTextField.tag;
break;
default:
break;
}
// check bounds of the intended index path and return if out of bounds
if ((destinationIndexPath.row == -1) || (destinationIndexPath.row >= [_tableView numberOfRowsInSection:[destinationIndexPath section]])) {
destinationIndexPath = currentIndexPath;
return;
}
/*
Animation for scrolling
*/
CGPoint current = [_tableView contentOffset];
// if we must animate up
if (destinationIndexPath.row < currentIndexPath.row)
{
// up code here
}
// if we must animate down
else if (destinationIndexPath.row > currentIndexPath.row)
{
// always scroll animate for down
[_tableView setContentOffset:CGPointMake(0, current.y + _tableView.rowHeight) animated:YES];
}
// if we only move left or right
else
{
// left and right code here
}
//update our current location
currentIndexPath = destinationIndexPath;
#catch (NSException *e)
{
return;
}
then after the animation is finished in the did finish animating method
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
{
//after the animation is done, set the responder
nextTextFieldSelection = (UITextField *)[[_tableView cellForRowAtIndexPath:currentIndexPath] viewWithTag:newTag];
NSLog(#"nexttextfield%#",nextTextFieldSelection);
if (nextTextFieldSelection)
{
//CRASH OCCURS HERE [nextTextFieldSelection becomeFirstResponder];
}
[self checkTextFieldIsDisabled];
}
By the end of that method I am in a new text field and we check if disabled. In reproducing this crash, it just exits because the textFields I am moving in to are not disabled.
Ive tried resigning the first responder before calling a new becomeFirstResponder but that doesn't seem to have any effect. Its possible I wasn't resigning in the proper location though. Any ideas where the memory issue would be?
Thanks
How can I check if a method is or isn't running, in an if statement? For example-
if ([(UIButton *)sender isEqual:blueButton] && **showBlueText method is running** )
{
Keep playing.
}
else if ([(UIButton *)sender isEqual:blueButton] && **showBlueText method is NOT running** )
{
Game over.
}
-(void)showBlueText
{
blueText.hidden = NO;
[self performSelector:#selector(hideText) withObject:nil afterDelay:textDelay];
[self performSelector:#selector(showGreenText) withObject:nil afterDelay:hideDelay];
}
Just to clarify, 'showBlueText' is a part of its own loop that runs independently of this if statement. I'm just trying to check if showBlueText is currently running.
You want to record state here. Make a new instance variable in this class.
// new iVar
BOOL textIsShowing;
// method
-(void)showBlueText {
textIsShowing = YES;
blueText.hidden = NO;
[self performSelector:#selector(hideText) withObject:nil afterDelay:textDelay];
}
// method
- (void)hideText {
textIsShowing = NO;
blueText.hidden = YES;
}
// button press
- (void)buttonPressed {
if (textIsShowing) {
NSLog(#"Keep playing");
} else {
NSLog(#"Game over");
}
}
Between the time you call this method, and the animation stops, don't think of it as "running". It schedules code to be executed later. Instead you want to be notified after it has finally run.
And in this case it's easiest to keep track of the state yourself. Use a new variable to track the state of things, and change it's value when that state changes.
But can't you just check if (blueText.hidden)? Yeah, you could. But it's bad practice to store state about your program in some obscure property of a random unimportant object.
Examine your state to figure out what you show. Don't examine what's showing to figure out your state.
I suggest replace Keep playing or Game over or Doing stuff with NSLog() statements. I always use it to keep a track of the changes in program if I am getting unexpected result.
So your statement may look like:
NSLog(#"Keep playing");
I hope this helps.
Just check if the text is hidden. No need to store parallel state in your controller - all that does is create the possibility that they'll be out of sync.
I have an iPhone application in which I am testing in the applicationDidBecomeActive: that if the selected viewcontroller's rootview is there, then I want to call one webservice, otherwise not when I am coming from background to foreground I am taking the stack and checking it. But now even if I am in the rootview the webservice is not getting called. Can anybody help me on this?
Here is my code snippet:
- (void)applicationDidBecomeActive:(UIApplication *)application{
NSLog(#"applicationWilssnd");
if(tabBarController.selectedIndex==0)
{
NSArray *mycontrollers = self.tabBarController.viewControllers;
NSLog(#"%#",mycontrollers);
///if([mycontrollers objectAtIndex:0]!=)
///[[mycontrollers objectAtIndex:0] popToRootViewControllerAnimated:NO];
PinBoardViewController *pinvc=(PinBoardViewController*)[[mycontrollers objectAtIndex:0]topViewController] ;
if([mycontrollers objectAtIndex:0]!=pinvc)
{
}
else
{
[pinvc merchantnews];
}
mycontrollers = nil;
tabBarController.selectedIndex = 0;
}
}
`here the merchantnews is not getting called.
PinBoardViewController *pinvc=(PinBoardViewController*)[[mycontrollers objectAtIndex:0]topViewController] ;
if([mycontrollers objectAtIndex:0]!=pinvc)
Instead of this, try this
PinBoardViewController *pinvc=(PinBoardViewController*)[[mycontrollers objectAtIndex:0]topViewController] ;
if(pinvc isKindOfClass:[PinBoardViewController class]){
// Do ur stuff
}
My application is a VOIP telephony toolbox.
I have a series of UISwitch controls, which the user can use to change their settings, for example if they want to alter their caller id settings.
When the user changes the setting I need to make a call to the Telephony platform over its Restful API. If the Restful call fails, then I would like to reset the switch back to its previous setting. eg If the user turns caller ID on, and it fails because of a connection failure, I would like the switch to revert back to off.
I implemented this in my switchChangedValue method, however it creates a nasty loop. When a failure happens I set the UISwitch to its previous setting, but it in turn calls the switchChangedValue method again, which fails and so on looping
Here is part of my switchChangedValue method, any ideas welcome.
//Check if its a valid response from the XSI server
if ([bs getHTTPResponseCode] >= 200 && [bs getHTTPResponseCode] < 300) {
//This is the successful case
}
else
{
// I throw an alert here
//Id really like to change the UISwitch back if it goes wrong but it causes a bad loop.
if (buttonstate == false){
[switchbutton setOn:YES animated:YES];
//This invokes my switchChangedValue again
}
else if (buttonstate == true){
[switchbutton setOn:NO animated:YES];
//This invokes my switchChangedValue again
} else{
NSLog(#"Something went bad");
}
[bs release];
You might try something like this:
Declare this in your header:
BOOL _fireAPICall;
Set it to YES whenever the particular class you're in is initialized:
- (id)init {
if (self = [super init]) {
...
_fireAPICall = YES;
...
}
return self;
}
Then:
if (_fireAPICall) {
if ([bs getHTTPResponseCode] >= 200 && [bs getHTTPResponseCode] < 300) {
// success
} else {
// failure
_fireAPICall = NO;
[switchbutton setOn:!buttonstate animated:YES];
}
} else {
_fireAPICall = YES;
// handle case where switch is turned off if necessary
}
This is assuming that you're not making an API call when the user manually turns the switch off, though - is that the case?
Updated above!