I would like to use the MFMailComposeViewController mailComposeDelegateproperty with completion block syntax, but not sure if that is possible. Something similar to how the TWTweetComposeViewController completionHandler property works:
TWTweetComposeViewController __weak *twee = tweeter;
tweeter.completionHandler = ^(TWTweetComposeViewControllerResult result) {
// code here
};
The code I have creates the MFMailComposeViewController, but then has to save a reference my viewController parameter, since this "share via email" functionality is not in a UIViewcontroller, but a custom MYSharing class.
MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
// more code here
_viewController = viewController;
picker.mailComposeDelegate = self;
[viewController presentModalViewController:picker animated:YES];
The mailComposeController:didFinishWithResult:error: from MFMailComposeViewControllerDelegate uses that _viewController to dismiss the modal.
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error {
[_viewController dismissModalViewControllerAnimated:YES];
}
Not understanding blocks very well, is there some syntax that look like this?
picker.mailComposeDelegate = ^(???)(??? ??? ???) {
[viewController dismissModalViewControllerAnimated:YES];
}
I did find MFMailComposeViewController(BlocksKit) (which has source on github), but even with that, the syntax conversion trips me up.
No completion handler for MFMailComposeViewController now.
if you want to reference the view controller who presented the MFMailComposeViewController, code like below, use presentingViewController property.
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error {
[controller.presentingViewController dismissModalViewControllerAnimated:YES];
}
Why don't you just call [self dismissModalViewControllerAnimated:YES]; from the MFMailComposeViewControllerDelegate method?
Related
I'm using a subclass of the PFLogInViewController in which I want to display errors in a different way to that of the default behaviour which is to pop up a UIAlertView.
Does anyone know if there's a way to avoid showing the UIAlertView? I'm already using the following method, however that doesn't actually allow me to avoid the UIAlertView being shown in the event of a failed login.
- (BOOL)logInViewController:(PFLogInViewController *)logInController shouldBeginLogInWithUsername:(NSString *)username password:(NSString *)password
PFLogInViewController does not provide hooks to change this behavior. You might want to build your own custom PFLogInViewController subclass and override the method which display alert view when login failed.
Since PFLogInViewController's code has been open sourced, according to it the method which displays an alert view is _loginDidFailWithError.
https://github.com/ParsePlatform/ParseUI-iOS/blob/master/ParseUI/Classes/LogInViewController/PFLogInViewController.m#L382-L390
- (void)_loginDidFailWithError:(NSError *)error {
if (_delegateExistingMethods.didFailToLogIn) {
[_delegate logInViewController:self didFailToLogInWithError:error];
}
[[NSNotificationCenter defaultCenter] postNotificationName:PFLogInFailureNotification object:self];
NSString *title = NSLocalizedString(#"Login Error", #"Login error alert title in PFLogInViewController");
[PFUIAlertView showAlertViewWithTitle:title error:error];
}
For example, if you like the following, you can not to display alerts when the login fails.
Define MYLogInViewController as subclass of PFLogInViewController
#interface MYLogInViewController : PFLogInViewController
#end
#implementation MYLogInViewController
- (void)_loginDidFailWithError:(NSError *)error {
if ([self.delegate respondsToSelector:#selector(logInViewController:didFailToLogInWithError:)]) {
[self.delegate logInViewController:self didFailToLogInWithError:error];
}
[[NSNotificationCenter defaultCenter] postNotificationName:PFLogInFailureNotification object:self];
}
#end
and use it instead PFLogInViewController
MYLogInViewController *logInViewController = [[MYLogInViewController alloc] init];
logInViewController.delegate = self;
[self presentViewController:logInViewController animated:YES completion:nil];
I have been struggling with this problem for a while now, so any help would be greatly appreciated.
Here is the situation: My application has a UIViewController subclass called InitialViewController. This view controller has a UIButton, and when that button is pressed it creates a NSObject subclass called MyEngine. Something like this:
#interface InitialViewController : UIViewController <MyEngineDelegate>
...
#end
#implementation InitialViewController
...
-(IBAction)pressedButton:(id)sender {
MyEngine *engine = [[MyEngine alloc] init];
[engine start];
}
Inside start, I present a ViewController (ConflictViewController) modally to get the user's choice:
#interface MyEngine : NSObject <ConflictViewControllerDelegate>
...
-(void) start;
#end
#implementation MyEngine
...
-(void) start {
ConflictViewcontroller *cvc = [[ConflictViewController alloc] initWithNibName:#"ConflictViewController" bundle:nil];
cvc.modalPresentationStyle = UIModalPresentationFormSheet;
cvc.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
cvc.delegate = self;
UIWindow *window = [(MyAppDelegate *) [[UIApplication sharedApplication] delegate] window];
[[window rootViewController] presentModalViewController:cvc animated:YES];
}
#end
ConflictViewController is really simple. It just waits for the user to decide, and when the user press the button, it send the message to the delegate, and dismiss itself.
-(IBAction)didSelectConflict:(id)sender {
UISegmentedControl *seg = (UISegmentedControl*) sender;
[self.delegate didResolveConflictChoice:seg.selectedSegmentIndex];
[self dismissModalViewControllerAnimated:YES];
}
I've checked every connection, all the delegates are working properly.
What is going wrong is:
When MyEngine receives the user's choice in it's implementation of didSelectConflict: it cannot continue properly because all of it's properties have gone null.
When the MyEngine presents the ConflictViewController, the program continues the execution and when start finishes, it goes back to pressedButton: and when this method is closed, the MyEngine object gets released.
What i want to know is if there is way around this ? Has anyone done something like this in another way ?
The question here is: How to get the user's choice properly when the choice is too complex to use UIAlertView.
Sorry for the long question, I simplified it as much as I could. Thanks for your time, any links, comments, or any kind of help is greatly appreciated
Why are you initializing MyEngine *engine in the IBAction, if you wish to use a MyEngine object why don't you make a global declaration in your InitialViewController and just call [engine start] in the IBaction. Then when the delegate method returns the selected index you can apply that to a global int in your initial view controller and continue on your way. Hope that makes sense
Make your method start as
-(void) startWithDelegate:(id)del {
ConflictViewcontroller *cvc = [[ConflictViewController alloc] initWithNibName:#"ConflictViewController" bundle:nil];
cvc.modalPresentationStyle = UIModalPresentationFormSheet;
cvc.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
cvc.delegate = del;
UIWindow *window = [(MyAppDelegate *) [[UIApplication sharedApplication] delegate] window];
[[window rootViewController] presentModalViewController:cvc animated:YES];
}
and
-(IBAction)pressedButton:(id)sender {
MyEngine *engine = [[MyEngine alloc] init];
[engine startWithDelegate:self];
}
implement didResolveConflictChoice: in InitialViewController and get the delegate call there.
OR you can use UIActionSheet if suitable.
I have some code that shows two UIViewController in a delegate.
RootViewController.m
request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:#"***some https url here ***"]];
// custom implementation of NSURLConnectionDelegate
dataman = [[DataManager alloc] initWithParentcontroller:self];
mainConn = [[NSURLConnection alloc] initWithRequest:request delegate:dataman];
In AuthenticationViewController.h
#protocol ShowAuthenticationWindowDelegate <NSObject>
#required
- (void) onFinishedEnteringCredentials:(NSURLCredential*)credentials;
- (void) onCancelAuthentication;
#end
in AuthenticationViewController.m
- (IBAction) onClickLogin:(id)sender;
{
....
// authDelegate => id <ShowAuthenticationWindowDelegate>
[authDelegate onFinishedEnteringCredentials:credentials];
[self dismissModalViewControllerAnimated:YES];
....
}
in DataManger.h (DataManager class) implements the NSURLConnectionDelegate and ShowAuthenticationWindowDelegate.
In Datamanager.m
In the didReceiveAuthenticationChallenge delegate function I show the AuthentiationViewController as a modal dialog to gather username/password.
-(void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
AuthenticationViewController *authview = [[AuthenticationViewController alloc] initWithNibName:#"AuthenticationViewController" bundle:[NSBundle mainBundle]];
authview.modalPresentationStyle = UIModalPresentationFullScreen;
authview.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
authview.credentialsDelegate = self;
[rootController presentModalViewController:authview animated:YES];
}
Here I show a UIViewController which is an activity indicator in a view. I am showing it modally after I dismiss the previous AuthenticationViewController dialog in one of the login button event handler by called dismissModalViewController. After sending the credentials with challenge object (previously cached) I am showing the ActivityViewController modally, but it is not shown no matter what I do. I tried to show an UIAlertView which works, but my activityviewcontroller is not shown. I checked the parameters and objects everything is valid. even the delegate wire ups!!! All the code is getting called but the dialog is not shown.
May be I am missing something ???
- (void) onFinishedEnteringCredentials:(NSURLCredential*)credentials;
{
[[authChallenge sender] useCredential:credentials forAuthenticationChallenge:authChallenge];
// create an activity modal dialog
if (activityController == nil) {
activityController = [[ActivityViewController alloc] initWithNibName:#"ActivityViewController" bundle:[NSBundle mainBundle]];
activityController.modalPresentationStyle = UIModalPresentationFullScreen;
activityController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
}
[rootController presentModalViewController:activityController animated:YES];
}
I have figure out the solution, if anyone want to show two modal dialogs back to back, you should set the "animated" parameter to "NO" on the controller that is being dismissed. It seems like the animation transition is not being completed by the time the next controller is shown with "presentViewController" function.
I am calling the leader board like this:
-(void)viewscores:(SPEvent*)event
{
GKLeaderboardViewController *leaderboardController = [[GKLeaderboardViewController alloc] init];
if (leaderboardController != nil) {
leaderboardController.leaderboardDelegate = self;
UIWindow* window = [UIApplication sharedApplication].keyWindow;
[window addSubview: self.rootViewController];
[self presentModalViewController: leaderboardController animated: YES];
}
}
When I Click the leader board button, I receive an error:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[UIViewController presentModalViewController:animated:]: unrecognized selector sent to class 0x3e2fc7f8'
Is this normal?
You should probably call the function in a viewController. In one of my app's the code looks like this:
-(IBAction)showLeaderBoard {
GKLeaderboardViewController *leaderBoardCont = [[GKLeaderboardViewController alloc] init];
if (leaderBoardCont) {
leaderBoardCont.category=#"1S";
leaderBoardCont.timeScope=GKLeaderboardTimeScopeWeek;
leaderBoardCont.leaderboardDelegate=self;
[self presentModalViewController:leaderBoardCont animated:YES];
}
}
and then you should also implement the delegate method:
-(void) leaderboardViewControllerDidFinish:(GKLeaderboardViewController *)viewController {
[self dismissModalViewControllerAnimated:YES];
viewController = nil;
}
Here 1S is the identifier for the leader board you created in iTunes Connect. Hope this helps.
Edit: since you are still having problems, check these tutorials out. They cover everything about leader boards and achievements.
1st part
2nd part
You're sending the presentModalViewController message to an object that doesn't recognize it. So the class you wrote in your "Game.m" file doesn't inherit from UIViewController. Dunno what framework you're using, but you'll have to init a UIViewController instance to show the GameCenter view.
My code below crashes if I have the code in windowWillClose: that releases
my MyWindowController, otherwise it works fine.
I test it on Mac OS 10.6.8.
I am using XCode 3.1.3.
What have I done wrong?
It seems like the window is not disposed of before I release MyWindowController,
because it crashes in a NSTableView method.
My button handler calls [NSApp stopModalWithCode:0];
MyDialog()
{
MyWindowController* controller = [[MyWindowController alloc] init];
[controller showWindow:controller];
NSWindow* window = [controller window];
[NSApp runModalForWindow:window];
[window close];
}
In my MyWindowController:
- (void)windowWillClose:(NSNotification*)notification
{
[self autorelease];
}
You are releasing 'self' in windowWillClose - that seems wrong.
Surely anything like that should be done in dealloc?
-(void)dealloc
{
[super dealloc];
}
Also, you might be better autoreleasing controller when it is initially alloc'd?