I am creating and iPad application using XCode version 4.3.2. I am having trouble figuring out how to close a popover that is created in a storyboard.
On my main screen I have a button. On the storyboard, I have a segue defined from that button to my popover. My popover is a table view controller. After selecting an item in the popover table view, I am sending the selected information back to the parent and attempting to close the popover. Everything works except I cannot get the popover to close.
The code for the main screen .m file:
#import "SectionViewController.h"
#import "SortByTableViewController.h"
#interface SectionViewController () <SortByTableViewControllerDelegate>
#end
#implementation SectionViewController
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"DisplaySortByOptions"])
{
SortByTableViewController *popup = (SortByTableViewController*)segue.destinationViewController;
popup.selectedSection = self.selectedSection;
popup.receivedOption = self.selectedItemCharacteristic;
popup.delegate = self;
}
}
- (void)sortByTableViewController:(SortByTableViewController *)sender
returnedOption:(ItemCharacteristic *)returnedOption
{
if(!returnedOption)
{
[self.sortByButton setTitle:#"SHOW ALL" forState:UIControlStateNormal];
}
else
{
[self.sortByButton setTitle:returnedOption.name forState:UIControlStateNormal];
}
self.itemCharacteristic = returnedOption;
[self dismissViewControllerAnimated:YES completion:nil]; //THIS DOES NOT CLOSE THE POPOVER
}
The code for the popover .h file:
#import <UIKit/UIKit.h>
#class SortByTableViewController;
#protocol SortByTableViewControllerDelegate <NSObject>
- (void)sortByTableViewController:(sortByTableViewController *)sender
returnedOption:(ItemCharacteristic *)returnedOption;
#end
#interface SortByTableViewController : UITableViewController
#property (nonatomic, strong) Section *selectedSection;
#property (nonatomic, strong) ItemCharacteristic *receivedOption;
#property (nonatomic, weak) id <SortByTableViewControllerDelegate> delegate;
#end
The code for the popover .m file:
#import "SortByTableViewController.h"
#interface SortByTableViewController () <UITableViewDelegate>
#end
#implementation SortByTableViewController
#synthesize selectedSection = _selectedSection;
#synthesize receivedOption = _receivedOption;
#synthesize delegate = _delegate;
...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
ItemCharacteristic *itemCharacteristic = [self.fetchedResultsController objectAtIndexPath:indexPath];
[self.delegate sortByTableViewController:self returnedOption:itemCharacteristic];
[self dismissViewControllerAnimated:YES completion:nil]; //THIS DOESN'T WORK
[self.navigationController popViewControllerAnimated:YES]; //THIS DOESN'T WORK EITHER
}
#end
Thanks for any help or guidance.
I found the answer. I had to add the following property to my main screen:
#property (nonatomic, strong) UIPopoverController *sortByPopoverController;
Then, when launching the popover, I included this:
UIStoryboardPopoverSegue *popoverSegue = (UIStoryboardPopoverSegue *)segue;
self.sortByPopoverController = popoverSegue.popoverController;
Including that code allowed me to properly dismiss the popover when the delegate called back:
[self.sortByPopoverController dismissPopoverAnimated:YES];
in swift just call this
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
self.dismissViewControllerAnimated(true, completion: nil)
}
Related
It's possible to change an image by clicking on a button inside an other View Controller?
I use this code in order to pass the data from the ViewController to the SecondViewController. I would want to add to the same button the commando to add an image to the SecondViewController... Excused my poor question...
ViewController.h
#import <UIKit/UIKit.h>
#import "SecondViewController.h"
#interface ViewController : UIViewController <SecondViewControllerDelegate> {
IBOutlet UITextField *userNameTextField;
}
#property (nonatomic, strong) UITextField *userNameTextField;
#end
ViewController.m
#import "ViewController.h"
#import "SecondViewController.h"
#interface ViewController ()
#end
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:#"to2"]){
SecondViewController *viewController = segue.destinationViewController;
viewController.delegate = self;
}
}
- (void)done:(NSString *)name{
[self dismissViewControllerAnimated:YES completion:nil];
NSLog(#"Back in first ViewController, metod Done, with name=%#",name);
userNameTextField.text=name;
}
#end
SecondViewController.h
#import <UIKit/UIKit.h>
#protocol SecondViewControllerDelegate <NSObject>
-(void) done:(NSString*)someText;
#end
#interface SecondViewController : UIViewController {
IBOutlet UITextField *someText;
IBOutlet UIButton *returnButton;
id delegate;
}
#property (nonatomic, assign) id <SecondViewControllerDelegate> delegate;
#property (nonatomic, strong) UITextField *someText;
- (IBAction)returnButtonPressed:(id)sender;
#end
SecondViewController.m
#import "SecondViewController.h"
#interface SecondViewController ()
#end
#implementation SecondViewController
#synthesize someText;
#synthesize delegate = _delegate;
- (IBAction)returnButtonPressed:(id)sender {
[self.delegate done:someText.text];
}
#end
Here is one way that should work for you:
Just set up an NSNotification in your ViewController with the image. Trigger the notification in the other viewController when the button is pressed.
in your image's view controller:
//in ViewDidLoad:
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(changeTheImage) name:#"CHANGE_THE_IMAGE" object:nil];
//then elsewhere in the class:
- (void)changeTheImage {
//change your image here
}
//and in your dealloc, make sure you add this, or it will keep "observing"
[[NSNotificationCenter defaultCenter] removeObserver:self];
Then in the button view controller:
//have this as your button action (or add the line to your button action)
- (IBAction)yourButtonWasPressed:(id)sender {
[[NSNotificationCenter defaultCenter]postNotificationName:#"CHANGE_THE_IMAGE" object:self];
What's the mean to change another UIViewController. because when you click on current UIViewController that's mean the current is on top and visible. what you called another can only be overlap inactive or it's does not exist right now.
So if you want somehow to change the UIImage from another UI, the simplest way is to hold the UIImage or image file name in a global store area such as your AppDelegate class, file. when click change the global area content. and in the ui for image show you can add some code in
- (void)viewWillAppear:(BOOL)animated {
//read and change UIImage content from global store
}
is it what you want ?
I've got a Master-Detail Applicaton in Xcode with a TableView and a SearchDisplayController.
In the TableView I have got a NSArray with 10 entries.
If I use the Searchbar, the DetailView shows correctly the entry I clicked on.
But if I do not use the Searchbar and click in the TableView on an entry, the DetailView every time shows me the first entry of the TableView.
What can I do to fix it?
MasterViewController.m: http://i.imgur.com/ZS1Oe.png
MasterViewController.h:
#import <UIKit/UIKit.h>
#interface DPMasterViewController : UITableViewController
#property (nonatomic, strong) IBOutlet UITableView *tableView;
#end
DetailViewController.m: http://i.imgur.com/AkVJ8.png
DetailViewController.h:
#import <UIKit/UIKit.h>
#interface DPDetailViewController : UIViewController
#property (strong, nonatomic) id detailItem;
#property (strong, nonatomic) IBOutlet UILabel *detailDescriptionLabel;
#end
Sorry that I use pictures, but I think it is easier for you to check. :)
I hope you can help me!
If anything is missing, just tell me.
EDIT:
In This Method after the else every time the indexPath.row = 0. I don't know how to fix it :(
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"showDetail"]) {
DPDetailViewController *destViewController = segue.destinationViewController;
NSIndexPath *indexPath = nil;
if ([self.searchDisplayController isActive]) {
indexPath = [self.searchDisplayController.searchResultsTableView indexPathForSelectedRow];
destViewController.detailItem = [searchItemList objectAtIndex:indexPath.row];
} else {
indexPath = [self.tableView indexPathForSelectedRow];
destViewController.detailItem = [itemList objectAtIndex:indexPath.row];
}
}
}
It looks like you are not performing any actions when you click on a cell of the tableView that is not part of the searchDisplayController, so try to change your tableView:didSelectRowAtIndexPath: method to
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self performSegueWithIdentifier:#"showDetail" sender:self];
}
I could use some help with custom delegates. I'm trying to make a protocol that sends a message to its delegate to dismiss the popover view. Here is what I'm trying.
In the popoverViewController.h
#import <UIKit/UIKit.h>
#protocol MyPopoverDelegate <NSObject>
-(void) didSelectLanguage;
#end
#interface Popover : UITableViewController{
id <MyPopoverDelegate> delegate;
NSMutableArray *languageData;
}
#property (nonatomic, assign) id <MyPopoverDelegate> delegate;
#end
.m
#synthesize delegate;
...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"You selected %#", [languageData objectAtIndex:[indexPath row]]);
[self.delegate didSelectLanguage];
}
...
And in the ViewController that presents the popover
#import <UIKit/UIKit.h>
#import "popoverViewController.h"
#interface ChoicesChoices : UIViewController <UIPopoverControllerDelegate, MyPopoverDelegate>{
UIPopoverController *popover;
}
- (IBAction)facebook:(id)sender;
- (IBAction)twitter:(id)sender;
- (IBAction)sms:(id)sender;
- (IBAction)copy:(id)sender;
- (IBAction)email:(id)sender;
- (IBAction)home:(id)sender;
- (IBAction)mute:(id)sender;
- (IBAction)note:(id)sender;
#property (nonatomic, retain) UIPopoverController* popover;
#end
and .m
#synthesize popover;
...
- (void)didSelectLanguage{
[popover dismissPopoverAnimated:YES];
NSLog(#"didSelectLanguage fired");
}
When I select a row in the table of the popover, didSelectLanguage does not get called. Any ideas on what I might be doing wrong? Thanks for your help.
Make sure you are setting your delegate to the be the view controller that is presenting your popover. Something like this in ChoicesChoices.m:
- (void)presentPopover
{
// assuming ARC for all allocations
Popover *myController = [Popover new];
myController.delegate = self;
self.popover = [[UIPopoverController alloc] initWithContentViewController:myController];
[self.popover presentPopover...]; // two flavors here, FromRect: and FromBarButtonItem:, that's left up to you to choose which one is correct.
}
Make sure you set the delegate in the presenting view controller when you create the instance of your custom class.
popover.delegate = self
Also, it looks like your property is a standard popover controller instead of an instance of your custom view controller.
I'm trying to assign SecondViewController as a delegate object of FirstViewController (if I understand correctly). However FirstViewController doesn't send any messages to SecondViewController.
Am I allowed to pretend as though SecondViewController did get a message from FirstViewController and respond to the FirstViewController? (Note: My SecondViewController is in charge of a view that has a button. When I press the button on my SecondViewController's view I want it to tell the FirstViewController to update its view)
FirstViewController.h
#import <UIKit/UIKit.h>
#protocol FirstViewControllerDelegate <NSObject>
#optional
- (void) setAnotherLabel;
#end
#interface FirstViewController : UIViewController {
IBOutlet UILabel *label;
id <FirstViewControllerDelegate> delegate;
}
#property (nonatomic, retain) IBOutlet UILabel *label;
#property (nonatomic, assign) id <FirstViewControllerDelegate> delegate;
- (void) pretendLabel;
- (void) realLabel;
#end
FirstViewController.m
#import "FirstViewController.h"
#implementation FirstViewController
#synthesize label;
#synthesize delegate;
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void) setAnotherLabel;
{
label.text =#"Real";
[self.view setNeedsDisplay];
}
- (void) pretendLabel;
{
label.text =#"Pretend";
[self.view setNeedsDisplay];
}
- (void) realLabel;
{
[self setAnotherLabel];
}
- (void)viewDidLoad
{
[super viewDidLoad];
label.text=#"Load";
[self pretendLabel];
}
...
#end
SecondViewController.h
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import "FirstViewController.h"
#interface SecondViewController : UIViewController <UIImagePickerControllerDelegate, UINavigationControllerDelegate, FirstViewControllerDelegate>
{
UIImage *image;
IBOutlet UIImageView *imageView;
}
- (IBAction) sendPressed:(UIButton *)sender;
- (IBAction) cancelPressed:(UIButton *)sender;
#end
SecondViewController.m
#import "SecondViewController.h"
#implementation SecondViewController
- (IBAction) sendPressed:(UIButton *)sender
{
FirstViewController *fvc = [[FirstViewController alloc] init];
[fvc setDelegate:self];
//how do I find out if I'm actually the delegate for FirstViewController at this point?
[fvc realLabel];
self.tabBarController.selectedIndex = 0;//switch over to the first view to see if it worked
}
There are a few issues with this and what appears to be a bit of confusion.
I assume that FirstViewController and SecondViewController are in separate tabs in the tab bar controller.
In the sendPressed: method, you're creating a new instance of FirstViewController - this is not the same FirstViewController that is in your tab bar controller and why calling realLabel has no effect.
The second point is that you appear to misunderstand how delegation works - there is no reason for a delegate in the code you posted.
Good read for getting to grips with delegates: http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/CocoaFundamentals/CommunicatingWithObjects/CommunicateWithObjects.html
As for a solution to your problem there are a few options:
Post a notification from SecondViewController that FirstViewController is observing (lots of information available on the net regarding notifications).
Get the specific instance of FirstViewController within the self.tabBarController.viewControllers array and call the method from there. Something like...
- (IBAction) sendPressed:(UIButton *)sender
{
for(UIViewController *controller in self.tabBarController.viewControllers)
{
if([controller isKindOfClass:[FirstViewController class]])
{
FirstViewController *firstViewController = (FirstViewController *)controller;
[firstViewController realLabel];
}
}
self.tabBarController.selectedIndex = 0;//switch over to the first view to see if it worked
}
There are more options available than this, but the above will give you a good start into researching the best approach for your need.
Hope this helps.
I have a simple project to present a modal view controller and transfer back a string based on which button in the modal VC that gets pressed. I based it all on watching the Stanford class on iTunes U. It looks like I have everything correct, but I get a couple of compiler warnings.
First I get one called passing argument 1 of 'setDelegate:' from incompatible pointer type in TransferViewController.m
Second I get four warnings called Invalid receiver type 'id <MyModalViewControllerDelegate>*' but these aren't displayed in the build results area, rather next to the offending lines in MyModalViewController.m, both lines in each of the button actions.
Here's the code...
// TransferViewController.h
#import <UIKit/UIKit.h>
#import "MyModalViewController.h";
#interface TransferViewController : UIViewController <MyModalViewControllerDelegate> {
UILabel *label;
UIButton *button;
}
#property (nonatomic, retain) IBOutlet UILabel *label;
#property (nonatomic, retain) UIButton *button;
- (IBAction)updateText;
#end
// TransferViewController.m
#import "TransferViewController.h"
#implementation TransferViewController
#synthesize label;
#synthesize button;
- (IBAction)updateText {
MyModalViewController *myModalViewController = [[MyModalViewController alloc] init];
myModalViewController.delegate = self; // I get the warning here.
[self presentModalViewController:myModalViewController animated:YES];
[myModalViewController release];
}
- (void)myModalViewController:(MyModalViewController *)controller didFinishSelecting:(NSString *)selectedDog {
label.text = selectedDog;
[self dismissModalViewControllerAnimated:YES];
}
#end
// MyModalViewController.h
#import <UIKit/UIKit.h>
#protocol MyModalViewControllerDelegate;
#interface MyModalViewController : UIViewController {
UIButton *abby;
UIButton *zion;
id <MyModalViewControllerDelegate> delegate;
}
#property (assign) id <MyModalViewControllerDelegate> delegate;
- (IBAction)selectedAbby;
- (IBAction)selectedZion;
#end
#protocol MyModalViewControllerDelegate <NSObject>
#optional
- (void)myModalViewController:(MyModalViewController *)controller didFinishSelecting:(NSString *)selectedDog;
#end
// MyModalViewController.m
#import "MyModalViewController.h"
#implementation MyModalViewController
#synthesize delegate;
- (IBAction)selectedAbby {
if ([self.delegate respondsToSelector:#selector (myModalViewController:didFinishSelecting:)]) {
[self.delegate myModalViewController:self didFinishSelecting:#"Abby"];
}
}
- (IBAction)selectedZion {
if ([self.delegate respondsToSelector:#selector (myModalViewController:didFinishSelecting:)]) {
[self.delegate myModalViewController:self didFinishSelecting:#"Zion"];
}
}
Get rid of those *s after id <something> and before delegate.
So make this
id <MyModalViewControllerDelegate> *delegate;
this
id <MyModalViewControllerDelegate> delegate;