So....I have a View Controller and when I press a button, another View Controller appears:
- (IBAction)searchButtonPressed:(id)sender {
[self presentViewController:self.controllerSearch animated:YES completion:nil];
}
Inside view controller number 2 is a table view and when a row is selected in a table this code runs:
NSString *phrase = nil; // Document password (for unlocking most encrypted PDF files)
NSString *filePath2 = filePath; assert(filePath2 != nil); // Path to first PDF file
LazyPDFDocument *document = [LazyPDFDocument withDocumentFilePath:filePath2 password:phrase];
if (document != nil) // Must have a valid LazyPDFDocument object in order to proceed with things
{
LazyPDFViewController *lazyPDFViewController = [[LazyPDFViewController alloc] initWithLazyPDFDocument:document];
lazyPDFViewController.delegate = self; // Set the LazyPDFViewController delegate to self
#if (DEMO_VIEW_CONTROLLER_PUSH == TRUE)
[self.navigationController pushViewController:lazyPDFViewController animated:YES];
#else // present in a modal view controller
lazyPDFViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
lazyPDFViewController.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentViewController:lazyPDFViewController animated:YES completion:NULL];
#endif // DEMO_VIEW_CONTROLLER_PUSH
}
else // Log an error so that we know that something went wrong
{
NSLog(#"%s [LazyPDFDocument withDocumentFilePath:'%#' password:'%#'] failed.", __FUNCTION__, filePath2, phrase);
}
Now I am using LazyPDFKit and it comes with this delegate method:
- (void)dismissLazyPDFViewController:(LazyPDFViewController *)viewController
{
// dismiss the modal view controller
[self dismissViewControllerAnimated:YES completion:NULL];
}
I put a break point and I can see my code goes into the delegate method, but the LazyPDFViewController does not go away.
I have tried the following:
[[[self presentingViewController] presentingViewController] dismissViewControllerAnimated:YES completion:nil];
but that takes me back a few view controllers to far.
Am I missing something?
Additional code in my first view Controller .h
#property (strong, nonatomic) UISearchController *controllerSearch;
and in first view controller .m
- (UISearchController *)controller {
if (!_controllerSearch) {
// instantiate search results table view
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Storyboard" bundle:nil];
LHFileBrowserSearch *resultsController = [storyboard instantiateViewControllerWithIdentifier:#"SearchResults"];
// create search controller
_controllerSearch = [[UISearchController alloc]initWithSearchResultsController:resultsController];
_controllerSearch.searchResultsUpdater = self;
// optional: set the search controller delegate
_controllerSearch.delegate = self;
}
return _controllerSearch;
}
If you are pushing the view controller:
[self.navigationController pushViewController:lazyPDFViewController animated:YES];
Then the code in the delegate doesn't make sense, because it assumes it is a modal view controller that needs to be dismissed:
- (void)dismissLazyPDFViewController:(LazyPDFViewController *)viewController
{
// dismiss the modal view controller
[self dismissViewControllerAnimated:YES completion:NULL];
}
But you've added it to the navigation stack (I assume).
If you can't pop it again from the navigation controller at this point you are missing some code in your example.
Are you sure your delegate is firing on the main thread? Try:
- (void)dismissLazyPDFViewController:(LazyPDFViewController *)viewController
{
dispatch_async(dispatch_get_main_queue(), ^{
[self.navigationController popViewControllerAnimated:YES];
});
}
try this:
- (void)dismissLazyPDFViewController:(LazyPDFViewController *)viewController
{
// dismiss the modal view controller
[[viewController presentingViewController] dismissViewControllerAnimated:YES completion:nil];
}
your code :
[[[self presentingViewController] presentingViewController] dismissViewControllerAnimated:YES completion:nil];
just went too far.
I just made the demo project based on your situation. And I am not facing any issue with it. So I think there might be some issue regarding how you are presenting the second controller.
In your button click, try this code:
- (IBAction)searchButtonPressed:(id)sender {
UIStoryboard *main = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
//idSecondVC is the storyboard id of second view controller
SecondVC *SecondVC = [main instantiateViewControllerWithIdentifier:#"idSecondVC"];
[self presentViewController:SecondVC animated:YES completion:nil];
}
And in your controller number 2, I just used the above code:
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 10;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
cell.textLabel.text = [NSString stringWithFormat:#"Cell %ld",indexPath.row];
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self openLazyPDF];
}
- (void)openLazyPDF
{
NSString *phrase = nil; // Document password (for unlocking most encrypted PDF files)
NSArray *pdfs = [[NSBundle mainBundle] pathsForResourcesOfType:#"pdf" inDirectory:nil];
NSString *filePath = [pdfs firstObject]; assert(filePath != nil); // Path to first PDF file
LazyPDFDocument *document = [LazyPDFDocument withDocumentFilePath:filePath password:phrase];
if (document != nil) // Must have a valid LazyPDFDocument object in order to proceed with things
{
LazyPDFViewController *lazyPDFViewController = [[LazyPDFViewController alloc] initWithLazyPDFDocument:document];
lazyPDFViewController.delegate = self; // Set the LazyPDFViewController delegate to self
#if (DEMO_VIEW_CONTROLLER_PUSH == TRUE)
[self.navigationController pushViewController:lazyPDFViewController animated:YES];
#else // present in a modal view controller
lazyPDFViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
lazyPDFViewController.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentViewController:lazyPDFViewController animated:YES completion:NULL];
#endif // DEMO_VIEW_CONTROLLER_PUSH
}
else // Log an error so that we know that something went wrong
{
NSLog(#"%s [LazyPDFDocument withDocumentFilePath:'%#' password:'%#'] failed.", __FUNCTION__, filePath, phrase);
}
}
#pragma mark - LazyPDFViewControllerDelegate methods
- (void)dismissLazyPDFViewController:(LazyPDFViewController *)viewController
{
// dismiss the modal view controller
[self dismissViewControllerAnimated:YES completion:NULL];
}
And for me everything is working fine.
Looks like you need to the same macro for present as dismiss. So, you wrote
#if (DEMO_VIEW_CONTROLLER_PUSH == TRUE)
[self.navigationController pushViewController:lazyPDFViewController animated:YES];
#else // present in a modal view controller
lazyPDFViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
lazyPDFViewController.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentViewController:lazyPDFViewController animated:YES completion:NULL];
#endif // DEMO_VIEW_CONTROLLER_PUSH
You thus need
#if (DEMO_VIEW_CONTROLLER_PUSH == TRUE)
[self.navigationController popViewControllerAnimated:YES];
#else // presented in a modal view controller
[self dismissViewControllerAnimated:YES completion:NULL];
#endif // DEMO_VIEW_CONTROLLER_PUSH
It's possible that you have switched off the main thread and you can always add an assert to be check or, as has been suggested, use a dispatch_async to be certain.
NSAssert([NSThread isMainThread)];
I prefer the assert, when I know all the flows through a piece of code, since it shows my assumptions to the future me (or another) and does not leave code that looks like it knows something I do not (oh, they are using dispatch_async onto main so there must be some other thread magic going on deeper down).
- (void)dismissLazyPDFViewController:(LazyPDFViewController *)viewController
{
if (![NSThread isMainThread])
{
dispatch_async(dispatch_get_main_queue(), ^
{
[self dismissLazyPDFViewController:viewController];
});
return;
}
if (viewController.navigationController)
{
[viewController.navigationController popViewControllerAnimated:YES];
}
else
{
[viewController dismissViewControllerAnimated:YES completion:nil];
}
}
Related
I have created a UITableView and set everything up so that it pulls the correct Data that I want on the table. The only issue I have is that when I click on an item, I want it to open that viewController
I have set the Storyboard ID up correctly so everything should work but please see my code below incase there's something obvious I've missed:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Navigation logic may go here. Create and push another view controller.
/*
<#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:#"<#Nib name#>" bundle:nil];
// ...
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
*/
UIViewController *newTopViewController;
if (indexPath.section == 0) {
NSString *identifier = [NSString stringWithFormat:#"%#", [self.section1 objectAtIndex:indexPath.row]];
newTopViewController = [self.storyboard instantiateViewControllerWithIdentifier:identifier];
} else if (indexPath.section == 1) {
NSString *identifier = [NSString stringWithFormat:#"%#", [self.section2 objectAtIndex:indexPath.row]];
newTopViewController = [self.storyboard instantiateViewControllerWithIdentifier:identifier];
}
else if (indexPath.section == 2) {
NSString *identifier = [NSString stringWithFormat:#"%#", [self.section3 objectAtIndex:indexPath.row]];
newTopViewController = [self.storyboard instantiateViewControllerWithIdentifier:identifier];
}
}
I can provide more info if needed
You use instantiateViewControllerWithIdentifier to create view controller objects.
But you are not presenting the created view controller object so add:
[self.navigationController presentViewController:newTopViewController animated:YES completion:nil];
If Identifiers are correct and you set segues in your storyboard then you can just call
[self performSegueWithIdentifier:indentifier sender:nil];
You need to either Push yournewTopViewController
[self.navigationController pushViewController:newTopViewController animated:YES];
Or Modally Present your newTopViewController
[self.navigationController presentViewController:newTopViewController animated:YES completion:nil];
in the end of your didSelectRowAtIndexPath Method.
To answer your question I believe you should first import all your .h files First.
Then you can go
if (indexPath.section == 0) {
FirstViewController *firstController = [[FirstViewController alloc] init];
[self presentViewController:firstController animated:YES completion:nil];
}
And so on and so forth
Is it possible to open different view controllers depending on witch table view cell user clicks? I tried to do that with:
[self presentViewController:obj animated:YES completion:nil];
but when next view is presented, there is no navigation bar and I can't go back to table view.
EDIT:
Here is MasterViewController class that I am using
#import "MasterViewController.h"
#interface MasterViewController () {
NSArray *viewArray;
}
#end
#implementation MasterViewController
#synthesize items,itemImges;
- (void)awakeFromNib
{
if ([[[UIDevice currentDevice] systemVersion] compare:#"7" options:NSNumericSearch] != NSOrderedAscending) {
self.preferredContentSize = CGSizeMake(320.0, 480.0);
}
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
self.clearsSelectionOnViewWillAppear = NO;
}
self.title = NSLocalizedString(#"MasterTitle",#"Options:");
[super awakeFromNib];
}
- (void)viewDidLoad
{
[super viewDidLoad];
items = [NSArray arrayWithObjects:#"Media Explorer",#"Live TV",#"Settings",nil];
itemImges = [NSArray arrayWithObjects:
[UIImage imageNamed:#"listicon_guide.png"],
[UIImage imageNamed:#"listicon_livetv.png"],
[UIImage imageNamed:#"listicon_settings.png"],
nil];
// Do any additional setup after loading the view, typically from a nib.
self.detailViewController = (DetailViewController *)[[self.splitViewController.viewControllers lastObject] topViewController];
MediaExpDetailViewController *DVCA = [self.storyboard instantiateViewControllerWithIdentifier:#"MediaExpDetailViewController"];
LiveTVDetailViewController *DVCB = [self.storyboard instantiateViewControllerWithIdentifier:#"LiveTVDetailViewController"];
SettingsDetailViewController *DVCC = [self.storyboard instantiateViewControllerWithIdentifier:#"SettingsDetailViewController"];
//Create Array of views
viewArray = [NSArray arrayWithObjects:DVCA, DVCB, DVCC, nil];
}
#pragma mark - Table View
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return items.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
NSString *object = items[indexPath.row];
UIImage *image = itemImges[indexPath.row];
cell.textLabel.text = [object description];
cell.imageView.image = image;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//for iPad
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
//something goes here
}
else { //for iPhone
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main_iPhone" bundle:nil];
MediaExpDetailViewController *objSynergy = (MediaExpDetailViewController *)[mainStoryboard instantiateViewControllerWithIdentifier:#"MediaExpDetailViewController"];
[self.navigationController pushViewController:objSynergy animated:YES];
}
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
}
#end
First set Storyboard IDs for your Next View controllers in Interface Builder and then.
-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Check Row and Select Next View controller
if (indexPath.row == 1)
{
// Push Selected View
UIViewController *view1 = [self.storyboard instantiateViewControllerWithIdentifier:#"StoryboardID"];
[self.navigationController pushViewController:view1 animated:YES];
}
}
That's because
[self presentViewController:obj animated:YES completion:nil];
Presents the new view controller modally (over top of the existing visible controller). If you want to push to a new view controller using your navigation controller, you'll want to use this. Of course you'll want to make sure that the view controller you're pushing from is embedded within a UINavigationController.
[self.navigationController pushViewController:obj animated:YES];
And to answer your first question, yes it absolutely is possible. Just add some condition logic to your didSelectRowAtIndexPath: UITableViewDelegate method.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (someCondition) {
[self.navigationController pushViewController:obj animated:YES];
}else{
[self.navigationController pushViewController:otherObj animated:YES];
}
}
Modally presented view controllers don't have navigation bars by default. You have to embed them in a UINavigationController, in order to have one. You should also implement how to dismiss the presented view controller by yourself, calling dismissViewControllerAnimated at the appropriate times.
However, I'd recommend to push your view controllers (with pushViewControllerAnimated), instead of presenting them modally, if you don't specifically need the modal functionality.
I'm trying to implement MWPhotoBrowser in my project. I've added all the delegates, but it still will not display the photo.
Here's my didSelectRowAtIndexPath:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self performSegueWithIdentifier:#"MWPhotoBrowserSegue" sender:self]
}
This is my segue method:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue identifier] isEqualToString:#"MWPhotoBorwserSegue"])
{
photoBrowser = [[MWPhotoBrowser alloc]initWithDelegate:self];
UINavigationController * nc = [[UINavigationController alloc]initWithRootViewController:photoBrowser];
nc.modalTransitionStyle = UIModalTransitionStyleCrossDisolve;
[photos addObject:[MWPhoto photoWithImage:[UIImage imageNamed:#"picasa.jpg"]];
[photoBrowser setCurrentPhotoIndex:0];
[self.navigationController presentViewController:nc animated:YES completion:nil];
}
}
The #ofPhotosInBrowser:
-(NSUInteger)numberOfPhotosInPhotoBrowser:(MWPhotoBrowser *)photoBrowser
{
return self.photos.count;
}
photoAtIndex:
- (MWPhoto *)photoBrowser:(MWPhotoBrowser *)photoBrowser photoAtIndex:(NSUInteger)index {
if (index < self.photos.count)
return [self.photos objectAtIndex:index];
return nil;
}
Here's what I get after the didSelectRowAtIndexPath: is called:
Edit for Solution:
MWPhotoBrowser will not display a photo unless you put self.title in the initWithStyle: method. I also forgot to add the viewWillDisappear and viewWillAppear
I think u need to call reload data on it. Check Mwphotobrowser.h for proper way to do it.
try this [[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self presentViewController:yourNewNavigationController animated:YES completion:nil];
}];
I'm trying to create an iPad application with a similar user interface to Apple's Mail application, i.e:
RootView controller (table view) on the left hand side of the split view for navigation with a multiple view hierarchy. When a table cell is selected a new table view is pushed on the left hand side
The new view on the left side can update the detail view.
I can accomplish both tasks, but not together.
I mean I can make a multi-level table view in the RootController.
Or I can make a single-level table view in the RootController which can update the detailViewController.
Can anyone tell me how to make a multi-level table in the RootController which can update a detailViewController?
There is more source code at the link but below is the method in which I presume I have to declare a new detailViewController (which has to be put in the UISplitViewController):
- (void)tableView:(UITableView *)TableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSDictionary *dictionary = [self.tableDataSource objectAtIndex:indexPath.row];
//Get the children of the present item.
NSArray *Children = [dictionary objectForKey:#"Children"];
//
if([Children count] == 0) {
/*
Create and configure a new detail view controller appropriate for the selection.
*/
NSUInteger row = indexPath.row;
UIViewController <SubstitutableDetailViewController> *detailViewController = nil;
if (row == 0) {
FirstDetailViewController *newDetailViewController = [[FirstDetailViewController alloc]initWithNibName:#"FirstDetailView" bundle:nil];
detailViewController = newDetailViewController;
}
if (row == 1) {
SecondDetailViewController *newDetailViewController = [[SecondDetailViewController alloc]initWithNibName:#"SecondDetailView" bundle:nil];
detailViewController = newDetailViewController;
}
// Update the split view controller's view controllers array.
NSArray *viewControllers = [[NSArray alloc] initWithObjects:self.navigationController, detailViewController, nil];
splitViewController.viewControllers = viewControllers//nothing happens.....
[viewControllers release];//
}
else {
//Prepare to tableview.
RootViewController *rvController = [[RootViewController alloc]initWithNibName:#"RootViewController" bundle:[NSBundle mainBundle]];
//Increment the Current View
rvController.current_level += 1;
//Set the title;
rvController.current_title = [dictionary objectForKey:#"Title"];
//Push the new table view on the stack
[self.navigationController pushViewController:rvController animated:YES];
rvController.tableDataSource = Children;
[rvController.tableView reloadData]; //without this instrucion,items won't be loaded inside the second level of the table
[rvController release];
}
}
Sorry, but I cannot post my source code as it contains sensitive information. When I have more time available I will create a separate project and upload the code somewhere.
Here are extracts of how I have done it so far (I welcome any feedback).
The RootViewController - Note I have 4 sections in my root table.
#pragma mark -
#pragma mark Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
// Detail view logic
NSUInteger section = indexPath.section;
UIViewController <SubstitutableDetailViewController> *detailViewController = nil;
if (section == 2) {
ProductSearchDetailView *viewController = [[ProductSearchDetailView alloc] initWithNibName:#"ProductSearchDetailView" bundle:nil];
detailViewController = viewController;
//[viewController release];
}
else {
DetailViewController *defaultDetailViewController = [[DetailViewController alloc] initWithNibName:#"DetailView" bundle:nil];
detailViewController = defaultDetailViewController;
//[defaultDetailViewController release];
}
// Navigation logic
switch (section) {
case 0:
{
break;
}
case 1:
{
break;
}
case 2:
{
// new Navigation view
ProductSearchViewController *viewController = [[ProductSearchViewController alloc] initWithNibName:#"ProductSearchViewController" bundle:nil];
viewController.navigationItem.backBarButtonItem.title = #"Back";
[self.navigationController pushViewController:viewController animated:YES];
[viewController release];
break;
}
case 3:
{
StoreLocatorNavController *viewController = [[StoreLocatorNavController alloc] initWithNibName:#"StoreLocatorNavController" bundle:nil];
viewController.navigationItem.backBarButtonItem.title = #"Back";
[self.navigationController pushViewController:viewController animated:YES];
[viewController release];
break;
}
}
// Update the split view controller's view controllers array.
NSArray *viewControllers = [[NSArray alloc] initWithObjects:self.navigationController, detailViewController, nil];
splitViewController.viewControllers = viewControllers;
[viewControllers release];
// Dismiss the popover if it's present.
if (popoverController != nil) {
[popoverController dismissPopoverAnimated:YES];
}
// Configure the new view controller's popover button (after the view has been displayed and its toolbar/navigation bar has been created).
if (rootPopoverButtonItem != nil) {
[detailViewController showRootPopoverButtonItem:self.rootPopoverButtonItem];
}
[detailViewController release];
}
NSNotificationCenter part
Add this to ProductSearchViewController:
#pragma mark -
#pragma mark Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSDictionary *itemAtIndex = (NSDictionary *)[self.productResults objectAtIndex:indexPath.row];
[[NSNotificationCenter defaultCenter] postNotificationName:#"updateProduct" object:itemAtIndex];
}
And finally, add this to ProductSearchDetailViewController:
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(updateTheProductDetails:) name:#"updateProduct" object:nil];
}
- (void)updateTheProductDetails:(NSNotification *)notification {
NSDictionary *productDictionary = [NSDictionary dictionaryWithDictionary:[notification object]];
// product name
_productName.text = [productDictionary objectForKey:#"ProductDescription"];
}
Hope it helps!
I am calling MFMailComposeViewController from a UITableViewController.
Problem is the delegate method is never called when I select Cancel or Send button in Mail compose window:
mailComposeController:(MFMailComposeViewController*)controllerdidFinishWithResult
Here is the table view class:
#implementation DetailsTableViewController
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section==0 && indexPath.row==4) {
//SEND MAIL
MFMailComposeViewController *controller = [[MFMailComposeViewController alloc] init];
controller.mailComposeDelegate = self;
if ([MFMailComposeViewController canSendMail]) {
[controller setSubject:[NSString stringWithFormat:#"Ref %#",[item objectForKey:#"reference"]]];
[controller setMessageBody:#" " isHTML:NO];
[controller setToRecipients:[NSArray arrayWithObject:[item objectForKey:#"email"]]];
[self presentModalViewController:controller animated:YES];
}
[controller release];
}
}
- (void)mailComposeController:(MFMailComposeViewController*)controllerdidFinishWithResult:(MFMailComposeResult)result error:(NSError*)error {
// NEVER REACHES THIS PLACE
[self dismissModalViewControllerAnimated:YES];
NSLog (#"mail finished");
}
The application doesn't crash. After the Cancel or Send button is pressed, the Compose Window stays on the screen with buttons disabled. I can exit application pressing Home key.
I am able to open other Modal Views form TableView but not MailCompose.
Make sure you use
controller.mailComposeDelegate = self;
and not
controller.delegate = self;
Your method signature is incorrect:
- (void)mailComposeController:(MFMailComposeViewController*)controllerdidFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
Should be:
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
Refer this article for full implementation : http://www.ioscreator.com/tutorials/send-email-from-an-app
working code after making removing deprecated one :
#import <MessageUI/MFMailComposeViewController.h>
#interface SettingsTableViewController () <MFMailComposeViewControllerDelegate, UITextFieldDelegate, UITextViewDelegate>
#end
#implementation SettingsTableViewController
// add default methods
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSInteger sectionNum = indexPath.section;
NSInteger rowNum = indexPath.row;
if (sectionNum == 2 && rowNum == 1) {
MFMailComposeViewController *controller = [[MFMailComposeViewController alloc] init];
controller.mailComposeDelegate = self;
if ([MFMailComposeViewController canSendMail]) {
[controller setSubject:[NSString stringWithFormat:#"Invitation to Northstar app"]];
[controller setMessageBody:#" " isHTML:NO];
// [controller setToRecipients:[NSArray arrayWithObject:[item objectForKey:#"email"]]];
//presentViewController:animated:completion:
[self presentViewController:controller animated:YES completion:NULL];
}
}
}
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
{
NSLog (#"mail finished");
[self dismissViewControllerAnimated:YES completion:NULL];
}
#end
I faced the same problem and was searching for a fix from past 2 days then I found a fix myself and you won't believe how minor it was.
In my case the view controller (say 'DetailsTableViewController' as per this question) from where I was presenting the MFMailComposeViewController is already being presented from some other view controller (say 'BaseViewController').
The issue was lying in the 'modalPresentationStyle' of 'DetailsTableViewController' while presenting it from BaseViewController.
The moment I changed it from 'UIModalPresentationFormSheet' to 'UIModalPresentationPageSheet' (for that matter any thing other than 'UIModalPresentationFormSheet') issue got resolved and mail controller delegate methods started firing as usual.
Note: I was already calling the below method in 'DetailsTableViewController' (for this example) so it didn't really matter for me which 'modalPresentationStyle' I was using.
- (void)viewWillLayoutSubviews{
[super viewWillLayoutSubviews];
self.view.superview.bounds = CGRectMake(0, 0, 1024, 768);
self.view.superview.backgroundColor = [UIColor clearColor];
}