Pressing Action button twice crashes app - objective-c

My app is crashing in the iPad simulator when I press the action button again once it has already been pressed to open my activity view. I am concerned that this will be an issue if the user wants to press the button again to close the Popover rather than touching outside of it. Any suggestions are appreciated :)
FYI the Action button is a UIToolbar button.
In the .h
#property (strong, nonatomic) UIPopoverController *popup;
#property (strong, nonatomic) UIPopoverController *activityViewProp;
In the .m:
-(IBAction)openUIActivityView:(id)sender {
UIActivityViewController *activityView = [[UIActivityViewController alloc]initWithActivityItems:#"Hello World" applicationActivities:nil];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
[self presentViewController:activityView animated:YES completion:^{
}];
} else {
self.popup = [[UIPopoverController alloc] initWithContentViewController:activityView];
[self.popup presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionDown animated:YES]; }}

Just check if you already have a popup, and do something else
-(IBAction)openUIActivityView:(id)sender {
if (self.popup) {
[self.popup dismiss ...];
}
else {
// show popup code
}
}

The problem is, a view controller can only present one other view controller at any given time. Currently, when your tap the button a second time, you try to present a new instance of UIActivityViewController, while an other is already presented.
You can fix this, by checking the value of your main view controller's presentedViewController property. If it is not nil (and actually of type UIActivityViewController) you can return from the action without doing anything:
- (IBAction)openUIActivityView:(id)sender {
if (!self.presentedViewController) {
// We have no presented view controller yet.
// <your current code here>
} else {
// We are already presenting a view controller.
// Either dismiss it, or don't do anything.
}

Related

Objective-C: How to switch the NSView by button click

I have different xib files with NSViewController attached to them. (Screenshot below)
One of xib file called StartMenuViewController which has a button. I want to click that button and change the view to DetectingUSBViewController.(Screenshot below)
The IBAction of that button is in StartMenuViewController.m file.
And I use AppController.m to control my main xib view.(NSWindow + NSView) (Screenshot below)
When the application runs, I try to initialize the StartMenuViewController fist by doing the following thing in my AppController.m file.
-(void)awakeFromNib{
[self initialize];
}
-(void) initialize
{
#autoreleasepool {
//mainViewController is a NSViewController and _mainView is a NSView which connect with Custom View in main xib
self.mainViewController = [[[StartMenuViewController alloc]initWithNibName:StartMenuView bundle:nil]autorelease];
[_mainView addSubview:[_mainViewController view]];
}
}
It works fine and it will show the StartMenuViewController.xib on the window at first, but I do not know how to change the view after clicking the button(FIND USB DRIVE). I want the current view changes to DetectingUSBViewController.xib.
Simplest way possible, assuming you have tied your USB button properly in, do the following :
- (IBAction)usbButton:(UIButton *)sender {
DetectingUSBViewController *second = [[DetectingUSBViewController alloc] initWithNibName:#"DetectingUSBView" bundle:nil];
[self presentViewController:second animated:YES completion:nil];
}
load the DetectingUSBViewController in startMenuViewController as DetectingUSBViewController* v1 = [[ViewCont1 alloc] initWithNibName:#"ViewCont1" bundle:nil]; now add or replace the view as [v1 view] in view where you want to add/replace.
You need to hook up your button to send an IBAction
You need a 'View for DetectingUSBViewController.xib'
=> one way (iOS like) is to use a ViewController. Subclass NSViewController and then alloc init a DetectingUSBViewController
Add the view. Don't present the VC (as there is no such thing in OSX)
//button click action
- (IBAction)usbButton:(UIButton *)sender {
//! Retain the VC
Self.detectingUSBViewController = [[DetectingUSBViewController alloc] initWithNibName:#"DetectingUSBView" bundle:nil];
//add the view
[_mainView addSubview:[_detectingUSBViewController view]];
}

Reusable button bars?

I'm implementing an IOS6 app using storyboards. I want every screen--excuse me, scene--for the app to have a view at the top containing different image buttons of different sizes. Tapping the buttons takes the user to different scenes of the app.
That's too complex for a UITabController, as far as I can tell. I tried making a separate view controller for that view and including the view in each scene, but any functionality in the view--such as the buttons--causes the app to crash.
It looks like I may have to implement this view in the storyboard in one scene, then copy and paste it into every other scene, wiring up the segues from every scene to every other scene. What a maintenance nightmare! Is there a better way?
Since you are trying to create a custom UITabBarController, you should use a container view controller. To do that:
Open your storyboard and add a custom UIVIewController (let's call it ContainerViewController).
Insert the UIVIews that represent your tabs into that controller and then insert another UIVIew (*currentView in the code below) that will take the rest of the screen. That's what the child controllers will use to display their scene.
Create a UIVIewController for each scene (child controller) you need, as you would normally, and give each of them a unique identifier (Identity Inspector -> Storyboard ID)
Now you have to add the following code your ContainerViewController:
#interface ContainerViewController ()
#property (strong, nonatomic) IBOutlet UIView *currentView; // Connect the UIView to this outlet
#property (strong, nonatomic) UIViewController *currentViewController;
#property (nonatomic) NSInteger index;
#end
#implementation ContainerViewController
// This is the method that will change the active view controller and the view that is shown
- (void)changeToControllerWithIndex:(NSInteger)index
{
if (self.index != index){
self.index = index;
[self setupTabForIndex:index];
// The code below will properly remove the the child view controller that is
// currently being shown to the user and insert the new child view controller.
UIViewController *vc = [self setupViewControllerForIndex:index];
[self addChildViewController:vc];
[vc didMoveToParentViewController:self];
if (self.currentViewController){
[self.currentViewController willMoveToParentViewController:nil];
[self transitionFromViewController:self.currentViewController toViewController:vc duration:0 options:UIViewAnimationOptionTransitionNone animations:^{
[self.currentViewController.view removeFromSuperview];
[self.currentView addSubview:vc.view];
} completion:^(BOOL finished) {
[self.currentViewController removeFromParentViewController];
self.currentViewController = vc;
}];
} else {
[self.currentView addSubview:vc.view];
self.currentViewController = vc;
}
}
}
// This is where you instantiate each child controller and setup anything you need on them, like delegates and public properties.
- (UIViewController *)setupViewControllerForIndex:(NSInteger)index {
// Replace UIVIewController with your custom classes
if (index == 0){
UIViewController *child = [self.storyboard instantiateViewControllerWithIdentifier:#"STORYBOARD_ID_1"];
return child;
} else {
UIViewController *child = [self.storyboard instantiateViewControllerWithIdentifier:#"STORYBOARD_ID_2"];
return child;
}
}
// Use this method to change anything you need on the tabs, like making the active tab a different colour
- (void)setupTabForIndex:(NSInteger)index{
}
// This will recognize taps on the tabs so the change can be done
- (IBAction)tapDetected:(UITapGestureRecognizer *)gestureRecognizer {
[self changeToControllerWithIndex:gestureRecognizer.view.tag];
}
Finally, each view you create that represents a tab should have it's own TapGestureRecognizer and a number for its tag.
By doing all this you will have a single controller with the buttons you need (they don't have to be reusable), you can add as much functionality you want in them (that's what the setupTabBarForIndex: method will be used) and you won't violate DRY.

Is there a way to navigate to other views using a UIActionSheet?

Is there is a way to use an Action sheet to navigate to another view?
I have a button - "Go" and an Action sheet that asks "Do you want to proceed?" and in it "Yes" and "Cancel"
Can I can navigate to another view when pressing yes?
Yes, it is possible. To do this, the viewController that represents the UIActionSheet needs to adopt UIActionSheetDelegate. Upon dismissing the action sheet with either Yes or Cancel, - actionSheet:didDismissWithButtonIndex: method gets called, and from there you can navigate to another view or just ignore it.
References:
http://developer.apple.com/library/ios/#documentation/uikit/reference/UIActionSheet_Class/Reference/Reference.html#//apple_ref/occ/cl/UIActionSheet
http://developer.apple.com/library/ios/#documentation/uikit/reference/UIModalViewDelegate_Protocol/UIActionSheetDelegate/UIActionSheetDelegate.html
Edit:
#interface MyViewController : UIViewController <UIActionSheetDelegate>
-(IBAction)showActionSheet:(id)sender;
#end
#implementation MyViewController
-(IBAction)showActionSheet:(id)sender {
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:#"Do you want to procced?" delegate:self cancelButtonTitle:#"Cancel" destructiveButtonTitle:#"YES" otherButtonTitles:nil];
[actionSheet showInView:self.view];
}
-(void) actionSheet: (UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex {
switch (buttonIndex) {
case 0: {
// for illustration
// let's assume (1) you have a navigation controller
// (2) you are using storyboard
// (3) in the storyboard, you have a viewController with identifier MyChildViewControllerIdentifier
MyChildViewController *mcvc = [self.storyboard instantiateViewControllerWithIdentifier:#"MyChildViewControllerIdentifier"];
[self.navigationController pushViewController:mcvc animated:YES];
break;
}
default:
break;
}
}
P.S. I didn't run it, if there is any error, let me know to fix it.
Dismiss the actionsheet and then [self presentmodalviewcontroller:myview animated:yes]

App Crashes when I connect an IBOutlet in a ViewController managed by a UITabBar

OK So I have an app that has a button that loads in a new view modally. This new view has a tab bar and is inserting subviews(with their own Xib Files) according to its tab bar item tag number. Everything works great, however when I connect an IBOutlet inside one of these subviews with Interface Builder it crashes the app when i go to that tab. The IBOutlet is a UITextField and is being populated through its filesOwner (that same xibs .h and .m files). I am getting no warnings when building. I have researched this for about a week now and have tried changing the files owner class inside of interface builder, I've tried to delete the views and recreate them and still nothing, I've tried to delete and rewrite my IBOutlets and delete and reconnect them in IB and still nothing.
BELOW IS MY CODE THAT ADDS THE SUBVIEWS ACCORDING TO TAG NUMBERS:
-(void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item{
if (item.tag == 2) {
if (classDescriptionsViewController_ == nil) {
classDescriptionsViewController_ = [[UIViewController alloc]initWithNibName:#"secondViewController" bundle:nil];
}
[self.view insertSubview:classDescriptionsViewController_.view belowSubview:tabBar];
if (currentViewController_ != nil && currentViewController_ != classDescriptionsViewController_) {
[currentViewController_.view removeFromSuperview];
}currentViewController_ = classDescriptionsViewController_;
}
if (item.tag == 1) {
[currentViewController_.view removeFromSuperview];
currentViewController_ = nil;
}
if (item.tag == 3) {
if (raceDescriptionsViewController_ == nil) {
self.raceDescriptionsViewController = [[UIViewController alloc]initWithNibName:#"raceDescriptionsViewController" bundle:nil];
}
[self.view insertSubview:raceDescriptionsViewController_.view belowSubview:tabBar];
if (currentViewController_ != nil && currentViewController_ != raceDescriptionsViewController_) {
[currentViewController_.view removeFromSuperview];
}currentViewController_ = raceDescriptionsViewController_;
}}
BELOW IS MY CODE THAT ADDS THE TEXT TO THE UITEXTFIELD (THE IBOUTLET):
- (void)viewDidLoad
{
[super viewDidLoad];
self.textField.text = #"PLEASE WORK!";
// Do any additional setup after loading the view from its nib.
}
I figured it out... I had to set the delegate for that viewcontroller.

How to signal when a view is done and returning?

I'm building an iphone app, and i have my first view call a second view when a button is pressed. The second view is a UIPicker with a button. When the button is pressed, I want to return the data from the UIPicker. How would i do this? Here is the code i have so far:
This is the Button that calls the subview
-(IBAction)DayView:(id)sender{
DayPickerViewController *DPView =[[DayPickerViewController alloc]
initWithNibName:nil bundle:nil];
[self presentModalViewController:DPView animated:YES];
//tried below, doesnt work
//[calc SetDay:[DPView Getrow]];
//DaysButton.titleLabel.text =#"%i",[DPView Getrow];
}
This is the pickerview's code:
-(IBAction)buttonPressed{
NSInteger row = [dayPicker selectedRowInComponent:0];
data = row;
[self dismissModalViewControllerAnimated:YES];
}
The approach you tried first works on Windows where you can open and close a modal dialog in a similar way that you enter and leave a function. However, iOS doesn't work like this.
The simplest approach is to add an instance variable in you second view that refers to the parent view. Then you can notify the parent view by directly calling an instance method:
Main view:
-(IBAction) dayView:(id)sender {
DayPickerViewController *dpView = [[DayPickerViewController alloc]
initWithNibName:nil bundle:nil];
dpView.parent = self;
[self presentModalViewController:dpView animated:YES];
}
-(void) viewController:(DayPickerViewController*)controller
didSelectRow:(NSInteger)row {
// the child view has been dismissed,
// do something with the selected row...
}
Child view:
#property(nonatomic, retain) WoWViewController* parent;
...
#synthesize parent;
-(IBAction) buttonPressed {
NSInteger row = [dayPicker selectedRowInComponent:0];
[self dismissModalViewControllerAnimated:YES];
[self.parent viewController:self didSelectRow:row];
}