UIButton not working in second time (objective-C) - objective-c

I have a button in my first screen for loading a small game here is the code:
- (IBAction)playButtonPressed:(id)sender
{
[self startGameWithConfig:[RootViewController singleplayerGameConfig]];
NSLog(#"play again");
}
and inside of my game page I have a button to back to the first screen when I used this button I can back but my playButtonPressed not working any more, it print the NSLog but
the button it's not loading the game any more
here is my return button:
- (IBAction)return:(id)sender {
RootViewController *b = [[RootViewController alloc] init];
[self presentModalViewController:b animated:YES];
}
would you please help me to this implementation
Thanks in advance!
and here is my startGamingWithConfig
- (void) startGameWithConfig:(GameConfig *)config
{
// fade in the loading screen to hide load time
[_loadingView setHidden:NO];
[_loadingView setAlpha:0.0f];
[UIView animateWithDuration:0.2f
delay:0.0f
options:UIViewAnimationOptionCurveLinear
animations:^{
[_loadingView setAlpha:0.0f];
}
completion:^(BOOL finished){
CardsViewCtrl* newController = [[CardsViewCtrl alloc] init];
newController.gameConfig = config;
AppDelegate *delegate = (AppDelegate *)[[UIApplication
sharedApplication] delegate];
[delegate.navController pushFadeInViewController:newController
animated:YES];
}];
}

It is a bit hard for me to understand where this code is since there are no headings but it looks like when you are attempting to go back to the RootViewController you are creating a new one and pushing that on the stack. You want to make sure that your topViewController is removed, not adding more views.
So for a starter try to replace return method:
- (IBAction)return:(id)sender {
RootViewController *b = [[RootViewController alloc] init];
[self presentModalViewController:b animated:YES];
}
with this:
- (IBAction)goBack:(id)sender {
[self dismissModalViewController];
}
I am not sure how you have your view hierarchy setup, but if you have a working navigationController than try using [self.navigationController popNavigationController:YES];

Related

Custom NSMenuItem-views glitch when scrolling NSMenu on low resolution screen

I'm having some glitchy bugs when I'm using my menu bar application on a low resolution screen. Please see screenshots below as illustration! Because of the reduced height of the lo-res screen my total NSMenu does not fit in the screen, and so automatically a scrollview appears so i can still get to all the different items.
The problem is that my cutsom NSMenuItems, which thus have custom NSViews with their own draw [drawRect:(NSRect)dirtyRect] method, are behaving glitchy when scrolling down, and back up. It's as if there are some drawing calls missing. I unfortunately do not know how to detect when the NSMenu is effectively scrolling, or simply to access this automagically created scrollview on the NSMenu class...
Any help much appreciated !
the drawing code of my view in my NSMenuItem.
- (void)drawRect:(NSRect)dirtyRect
{
if (self.enabled)
{
if (self.isHighlighted)
{
[self colorRectHighlighted:dirtyRect];
[self drawTextInRect:dirtyRect withState:CustomCheckMenuItemViewStateHiglighted];
[self drawStateIconWithColor:[NSColor whiteColor]];
}
else
{
[self drawTextInRect:dirtyRect withState:CustomCheckMenuItemViewStateNormal];
AppDelegate *appDelegate = (AppDelegate *)[[NSApplication sharedApplication] delegate];
if(appDelegate.menuIsInDarkMode)
{
[self drawStateIconWithColor:[NSColor colorWithWhite:1.0 alpha:0.9]];
}
else
{
[self drawStateIconWithColor:[NSColor selectedMenuItemIndicatorColor:([NSColor currentControlTint]==NSBlueControlTint)?YES:NO]];
}
}
}
else
{
[self drawTextInRect:dirtyRect withState:CustomCheckMenuItemViewStateNormal];
AppDelegate *appDelegate = (AppDelegate *)[[NSApplication sharedApplication] delegate];
if(appDelegate.menuIsInDarkMode)
{
[self drawStateIconWithColor:[NSColor colorWithRed:136/256.0 green:136/256.0 blue:136/256.0 alpha:0.9]];
}
else
{
[self drawStateIconWithColor:[NSColor colorWithWhite:0 alpha:0.1]];
}
}
}
EDIT:
I initialise the NSMenuItems with the sliders as this:
self.tiltSliderViewController = [[SlidingViewController alloc] initWithNibName:#"SlidingViewController" bundle:nil];
self.tiltSliderViewController.delegate = self;
[tiltSliderMenuItem setView:[self.tiltSliderViewController view]];
self.rotationSliderViewController = [[SlidingViewController alloc] initWithNibName:#"SlidingViewController" bundle:nil];
self.rotationSliderViewController.delegate = self;
[rotationSliderMenuItem setView:[self.rotationSliderViewController view]];
The viewcontrollers used here have the following implementation:
#interface SlidingViewController ()
#end
#implementation SlidingViewController
- (IBAction)valueChanged:(id)sender
{
float slider_value = [_slider floatValue];
[_slider setToolTip:[NSString stringWithFormat:#"%ld",
_slider.integerValue]];
[_delegate sliderValueChanged:slider_value sender:self];
}
#end
screenshots:
NORMAL
DOWN
UP AGAIN = GLITCH!!

Code seem do play as the order as I want

- (void)viewDidLoad {
[super viewDidLoad];
[self pingSplash];
UIViewController *next = [[self storyboard] instantiateViewControllerWithIdentifier:#"ViewController"];
[self.navigationController pushViewController:next animated:YES];
}
I mean to finish pinSplash then pushViewController, but it directly goto ViewController page, even without finishing pingSplash, what is a good way to do that kind of job?
For the pingSplash part:
- (void) pingSplash
{
SKSplashIcon *pingSplashIcon = [[SKSplashIcon alloc] initWithImage:[UIImage imageNamed:#"ping.png"] animationType:SKIconAnimationTypePing];
_splashView = [[SKSplashView alloc] initWithSplashIcon:pingSplashIcon backgroundColor:[UIColor grayColor] animationType:SKSplashAnimationTypeBounce];
_splashView.animationDuration = 5.0f;
[self.view addSubview:_splashView];
[_splashView startAnimation];
}
The pingSplash method returns as soon as it starts the animation which is why you end up pushing the view controller too soon.
There are a few ways to solve this. One way would be to pass a block to the pingSplash method that is run after an appropriate delay.
Here's one way:
Update the pingSplash method to take a completion handler block that is run after the 5 second delay.
- (void) pingSplash:(void (^)(void))completion
{
SKSplashIcon *pingSplashIcon = [[SKSplashIcon alloc] initWithImage:[UIImage imageNamed:#"ping.png"] animationType:SKIconAnimationTypePing];
_splashView = [[SKSplashView alloc] initWithSplashIcon:pingSplashIcon backgroundColor:[UIColor grayColor] animationType:SKSplashAnimationTypeBounce];
_splashView.animationDuration = 5.0f;
[self.view addSubview:_splashView];
[_splashView startAnimation];
if (completion) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_splashView.animationDuration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
completion();
});
}
}
Then update your viewDidLoad:
- (void)viewDidLoad {
[super viewDidLoad];
[self pingSplash:^{
UIViewController *next = [[self storyboard] instantiateViewControllerWithIdentifier:#"ViewController"];
[self.navigationController pushViewController:next animated:YES];
}];
}

NavigationBar not displaying properling when pushViewController

The problem is pretty simple to understand with pictures.
I have a UINavigationController that allow the user to switch between to views.
The first view contains a search bar and a table view like so :
The second is a basic view where information about the cell are display
When I click on the search bar, the navigation controller gets hidden and the search bar is now at the top.
Now, if I click on a cell, it goes to the second views, but the navigation bar is first hidden like below :
And then, it automatically appears like that :
I have tried a couple of things like show the navigation bar before pushing the next view controller but it is quite ugly..
Does anyone know how to have the show the navigation bar directly on the second view (like in the contact application)?
[UPDATE] : Code
AppDelegate.m (I'm talking about navigationcontroller2)
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
FirstViewController *viewController1 = [[FirstViewController alloc] initWithNibName:#"FirstViewController" bundle:nil];
SecondViewController *viewController2 = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
viewController1.managedObjectContext = [self managedObjectContext];
viewController2.managedObjectContext = [self managedObjectContext];
viewController1.viewController2 = viewController2;
UINavigationController *navigationcontroller1 = [[UINavigationController alloc] initWithRootViewController:viewController1];
[navigationcontroller1.navigationBar setTintColor:[UIColor lightGrayColor]];
UINavigationController *navigationcontroller2 = [[UINavigationController alloc] initWithRootViewController:viewController2];
[navigationcontroller2.navigationBar setTintColor:[UIColor lightGrayColor]];
self.tabBarController = [[UITabBarController alloc] init];
self.tabBarController.viewControllers = [NSArray arrayWithObjects:navigationcontroller1, navigationcontroller2, nil];
self.window.rootViewController = self.tabBarController;
[self.window makeKeyAndVisible];
return YES;
}
FirstView.m
- (void) searchBarTextDidBeginEditing:(UISearchBar *)theSearchBar {
[self.navigationController setNavigationBarHidden:YES animated:YES];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (!noResultsToDisplay) {
PinDetailsViewController *pinDetailsViewController = [[PinDetailsViewController alloc] initWithNibName:#"PinDetailsViewController" bundle:nil];
NSManagedObject *managedObject = [fetchedResultsController objectAtIndexPath:indexPath];
Pin *pin = (Pin *) managedObject;
[self.navigationItem setTitle:#"Pins"];
[self.navigationController pushViewController:pinDetailsViewController animated:YES];
[pinDetailsViewController updateWithPin:pin];
}
}
If you need anything else, just ask but I think it's all there.
Try to use this code in each viewcontroller.
- (void) viewWillAppear:(BOOL)animated
{
[self.navigationController setNavigationBarHidden:NO animated:animated];
}
- (void) viewWillDisappear:(BOOL)animated
{
[self.navigationController setNavigationBarHidden:YES animated:animated];
}
Before you push the new view controller, you should unhide the navigation bar:
[self.navigationController setNavigationBarHidden:NO animated:YES];
I had a similar problem with the position of my navbar. Mine was moving up behind the status bar, and I fixed the issue by manually setting the navbar frame:
-(void)adjustNavBarOrigin
{
CGRect r = self.navigationController.navigationBar.frame;
r.origin = CGPointMake(0, 20); // 20 is the height of the status bar
self.navigationController.navigationBar.frame = r;
}
I had to call this method in a number of places, including viewWillAppear: and didRotateFromInterfaceOrientation:, but it worked a treat :)
Hiding the UINavigationBar can disturb the properties sometimes. Try using the property alpha instead of hidden.

UIAlertView showing up only after it's dismissed

I've been trying to figure this out for 2 days now, and before anyone posts another stackoverflow question, I've read them all and none of them cover my problem exactly:
I have a CoreData app that updates dynamically. Now during the update I want an UIAlertView to pop up saying that an update is being downloaded.
So here's the important code:
AppDelegate:
- (void)applicationDidBecomeActive:(UIApplication *)application
{
[myUpdater checkForUpdatesInContext:self.managedObjectContext];
}
_
Updater Class:
- (void)checkForUpdatesInContext:(NSManagedObjectContext *)myManagedObjectContext
{
[self loadUpdateTime];
NSLog(#"Update start");
NSDate *now = [NSDate dateWithTimeIntervalSinceNow:[[NSTimeZone localTimeZone] secondsFromGMT]];
if ([now timeIntervalSinceDate:updateTime] < UPDATE_TIME_INTERVAL)
{
return;
}
[self showAlertViewWithTitle:#"Update"];
... //updating process
[self.alertView dismissWithClickedButtonIndex:0 animated:YES];
NSLog (#"Update done");
}
- (void) showAlertViewWithTitle:(NSString *)title
{
self.alertView = [[UIAlertView alloc] initWithTitle:title message:#"Daten werden aktualisiert..." delegate:self cancelButtonTitle:nil otherButtonTitles:nil];
... //design the alertView
[self.alertView show];
NSLog (#"AlertView shows");
}
So here is what happens when I run this:
Launch image shows
NSLog "Update starts" fires
NSLog "AlertView shows" fires
Screen dims but no AlertView is shown
Update is running
NSLog "Update done" fires
Launch image goes away and TabBarController shows up
UIAlertView shows up and is dismissed right away and the dimmed screen returns to normal
What I would like to have happen:
Launch image
TabBarController shows up
Screen dims and UIAlertView shows
Update is running
UIAlertView gets dismissed and dimmed screen returns to normal
I know it's something with the UI Thread and the main Thread and stuff.. But I tried every combination it seems but still not the expected result. Please help :)
EDIT:
HighlightsViewController Class:
- (void)viewDidLoad
{
[super viewDidLoad];
self.updater = [[Updater alloc] init];
[updater checkForUpdatesInContext:self.managedObjectContext];
... // other setup stuff nothing worth mentioning
}
Is this the right place to call [super viewDidLoad]? Because it still doesn't work like this, still the update is being done while the Launch Image is showing on the screen. :-(( I'm about to give this one up..
Here you go, in this prototype things work exactly how you want them to.
Header:
#import <UIKit/UIKit.h>
#interface AlertViewProtoViewController : UIViewController
{
}
- (void) showAlertViewWithTitle:(NSString *)title;
- (void) checkForUpdatesInContext;
- (void) update;
- (void)someMethod;
- (void)someOtherMethod;
#end
#import "AlertViewProtoViewController.h"
Class:
#implementation AlertViewProtoViewController
UIAlertView *alertView;
bool updateDone;
UILabel *test;
bool timershizzle;
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.view.backgroundColor = [UIColor yellowColor];
UILabel *test = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 500, 500)];
test.backgroundColor = [UIColor blueColor];
[self.view addSubview:test];
[self performSelector:#selector(checkForUpdatesInContext) withObject:nil afterDelay:0.0];
}
- (void)update
{
//NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; //commented for auto ref counting
NSLog(#"update start");
//your update stuff
NSLog(#"update end");
updateDone = YES;
//[pool release];
}
- (void)checkForUpdatesInContext//:(NSManagedObjectContext *)myManagedObjectContext
{
//[self loadUpdateTime];
NSLog(#"Update start");
NSDate *now = [NSDate dateWithTimeIntervalSinceNow:[[NSTimeZone localTimeZone] secondsFromGMT]];
// if ([now timeIntervalSinceDate:updateTime] < UPDATE_TIME_INTERVAL)
// {
// return;
// }
[self showAlertViewWithTitle:#"Update"];
//[self setManagedObjectContext:myManagedObjectContext];
[self performSelector:#selector(someMethod) withObject:nil afterDelay:0.0];
[self performSelector:#selector(someOtherMethod) withObject:nil afterDelay:0.0];
}
-(void)someOtherMethod
{
while (!updateDone) {
// NSLog(#"waiting...");
}
[alertView dismissWithClickedButtonIndex:0 animated:YES];
NSLog (#"Update done");
self.view.backgroundColor = [UIColor greenColor];
}
-(void)someMethod
{
[self performSelectorInBackground:#selector(update) withObject:nil];
}
- (void) showAlertViewWithTitle:(NSString *)title
{
alertView = [[UIAlertView alloc] initWithTitle:title message:#"Daten werden aktualisiert..." delegate:self cancelButtonTitle:nil otherButtonTitles:nil];
alertView.frame = CGRectMake(100, 100, 200, 200);
alertView.backgroundColor = [UIColor whiteColor];
[self.view addSubview:alertView];
[self.view setNeedsDisplay];
NSLog (#"AlertView shows");
}
#end
You should adjust were needed for your own purposes but it works.
You are starting a background thread and then dismissing the alert immediately. I would suggest that you might use an NSNotification, posted from the background task, and received in whichever controller starts the alert, triggering a method that dismissed the alert.
I find the UIAlertView interface unsuitable for this type of user notice, and prefer to use a semi-transparent overlay view with a UIActivityIndicatorView, plus an informing message for the user.
You are doing a:
- (void)applicationDidBecomeActive:(UIApplication *)application
Isn't it so that the alertview you want to show needs a view to be loaded which isn't active yet at this point? See: http://developer.apple.com/library/ios/#documentation/uikit/reference/UIAlertView_Class/UIAlertView/UIAlertView.html
Similar question? UIAlertView starts to show, screen dims, but it doesn't pop up until it's too late!

How to get rid of EXC_BAD_ACCESS

So, another EXC_BAD_ACCESS topic on StackOverflow, but as I'm new to Objective-C this is still a topic I don't really grasp yet. Even though I have done a lot of research about it already.
The issue is the following. I have a UIScrollView that I have overwritten using a Custom Class (named MultiSelectView). If the user taps this UIScrollView and then I want to open a view that allows him to select some data.
So I have declared a UITapGestureRecognizer that calls the openMultiSelect: method. But on the line [parent.navigationController pushViewController:view animated:YES]; I get a Program received signal: "EXC_BAD_ACCESS". error. Why o why?
- (id) initWithCoder:(NSCoder *) coder {
self = [super initWithCoder: coder];
if (self) {
// Add a Tap Gesture Recognizer to the Scrollview.
// If the user taps the view, it triggers the 'openMultiSelect' method.
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(openMultiSelect:)];
[singleTap setNumberOfTapsRequired:1];
[singleTap setNumberOfTouchesRequired:1];
[self addGestureRecognizer:singleTap];
}
return self;
}
- (void)openMultiSelect:(UIGestureRecognizer *)gesture {
//int myViewTag = gesture.view.tag; // now you know which view called
DataSelectView *view = [[DataSelectView alloc] initWithNibName:#"DataSelectView" bundle:[NSBundle mainBundle]];
view.allowMultiSelect = YES;
[parent.navigationController pushViewController:view animated:YES];
[view release];
}
So the parent that you see is a ViewController that contains the tab. Is there a better way to do this? Because for now I have thus a ViewController that contains Tabs. In its activateTab: method I thus create the tab and pass self along. I do the same in the viewDidLoad for that tab to pass the parent to the custom UIScrollView:
- (void) activateTab:(int)index {
... code ...
self.tab_Basic = [[TabBasic alloc] initWithNibName:#"TabBasic" bundle: [NSBundle mainBundle]];
self.tab_Basic.parent = self;
... code ...
}
You should make some change to your callback method. Something like that:
- (void)openMultiSelect:(UIGestureRecognizer *)gesture {
//int myViewTag = gesture.view.tag; // now you know which view called
if(gesture.state == UIGestureRecognizerStateEnded){
DataSelectView *view = [[DataSelectView alloc] initWithNibName:#"DataSelectView" bundle:[NSBundle mainBundle]];
view.allowMultiSelect = YES;
[parent.navigationController pushViewController:view animated:YES];
[view release];
}
}
What you are doing wrong is releasing the object "view" too early, don't release it until the view is popped. That should fix the problem.
- (void)openMultiSelect:(UIGestureRecognizer *)gesture {
//int myViewTag = gesture.view.tag; // now you know which view called
DataSelectView *view = [[DataSelectView alloc] initWithNibName:#"DataSelectView" bundle:[NSBundle mainBundle]];
view.allowMultiSelect = YES;
[parent.navigationController pushViewController:view animated:YES];