How do I create a UIAlertController in a webview? - objective-c

I've been searching on the forums and still don't really know how to use an UIAlertController in a webview. I found a couple of questions although I didn't really get how to fix it. I'm a beginner if you can't already tell. What I'm trying to do is, if the user's internet turns off a message shows up. Although I get an error. Here's the error I get.
No visible #interface for 'WebViewController' declares the selector 'presentedViewController:animated:completion:'
And here's my code in the WebViewController's .m file.
- (void) webView:(UIWebView*) webView didFailLoadWithError:(nonnull NSError *)error {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:#"No Internet Connection" message:#"You don't have an internet connection! Please be aware that some pages might not load correctly." preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *Okay = [UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleCancel handler:nil];
[alert addAction:Okay];
[self presentedViewController:alert animated:YES completion:nil];}

You've a typo — the method is presentViewController:animated:completion:, not present**ed**ViewController:animated:completion:. The 'present' is meant to be a verb, not an adjective — you're asking yourself to do something, not about something. So the error you've received is completely correct.
Change to:
[self presentViewController:alert animated:YES completion:nil];

Related

is it possible to show the alert message on top of another sharing dialog

Im using this code to try and show a alert message on the iphone
[[UIApplication sharedApplication].delegate.window.rootViewController presentViewController:alert animated:YES completion:nil];
it works fine.
But is it possible to show the alert message on top of another sharing dialog also shown using presentViewController:
at the moment it shows a warning in the console and the alert does not show, only shows the popup for the sharing activity?
I can get this to work using UIAlertView but that deprecated now
For future reference, it would be good to include the text of the warning you're receiving in the question as well.
My guess is it's along the lines of:
Warning: Attempt to present <UIAlertController: 0x7fe676036000> on <ViewController: 0x7fe674e02f50> which is already presenting <UIActivityViewController: 0x7fe67580f800>
Which basically indicates you can't present another view controller using a view controller that's already presenting a separate view controller.
One way you could work around this is to climb the presentedViewControllers to locate a view controller which isn't already presenting and then present from that (in your case you should only need to move up one presentedViewController to your UIActivityViewController).
Here's an example using the UIWindowScene to grab the rootViewController (iOS 13+), but should basically be the same idea for using the appDelegate's window as well:
- (IBAction)showShareSheetAndAlert:(id)sender {
UIImage *homerImage = [UIImage imageNamed:#"Homer"];
UIActivityViewController *shareSheet = [[UIActivityViewController alloc] initWithActivityItems:#[homerImage] applicationActivities:nil];
[self presentViewController:shareSheet animated:YES completion:^{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:#"Test Alert" message:#"Here's a test alert on top of a share sheet" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *dismissAction = [UIAlertAction actionWithTitle:#"Dismiss" style:UIAlertActionStyleDefault handler:nil];
[alert addAction:dismissAction];
UIWindowScene *windowScene = (UIWindowScene *)[[[[UIApplication sharedApplication] connectedScenes] allObjects] firstObject];
UIViewController *viewControllerToPresentOn = windowScene.windows.firstObject.rootViewController;
// keep climbing the presented view controllers until we find the top one which isn't presenting
while (viewControllerToPresentOn.presentedViewController != nil) {
viewControllerToPresentOn = viewControllerToPresentOn.presentedViewController;
}
[viewControllerToPresentOn presentViewController:alert animated:YES completion:nil];
}];
}
Which will result in this:

AppleTV UIAlertView equivalent

So I'm working on an in app purchase in a SpriteKit game on AppleTV, but in the event of an error with payment or any other variety of errors, I want to display an error. UIAlertView is how I did it on iOS, but that's not an option on tvOS. Is there something similar that could be done instead? Basically, I need something to popup describing the error and a button to dismiss the popup. The ability to add more buttons (like UIAlertView) would be icing.
Note: I have researched this a bit and most things seem to point to using TVML, however, I don't believe that's an option mixed in with SpriteKit. I'll accept an answer related to this if it explains how to import something TVML (which I know next to nothing about) and run it alongside SpriteKit. I assume I'm looking for an answer unrelated to TVML though.
Check tvOS UIAlertController class :
UIAlertController* alert = [UIAlertController alertControllerWithTitle:#"My Alert"
message:#"This is an alert."
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {}];
[alert addAction:defaultAction];
[self presentViewController:alert animated:YES completion:nil];
Edit : When using SpriteKit, last line is to replace with
UIViewController* controller = [UIApplication sharedApplication].keyWindow.rootViewController;
[controller presentViewController:alert animated:YES completion:nil];
Note that this class is also available in iOS since iOS 8 !

How to fix run-time error using UIAlertController

I have this code sitting in a UIVIewController (XCode 6.1, iOS 8.1.1):
[UIAlertController showActionSheetInViewController:self
withTitle:#"Test Action Sheet"
message:NSLocalizedString(#"Are you sure you want to delete ALL appointments?",nil)
cancelButtonTitle:#"Cancel"
destructiveButtonTitle:#"Yes"
otherButtonTitles:#[#"No"] // same as Cancel
tapBlock:^(UIAlertController *controller, UIAlertAction *action, NSInteger buttonIndex){
if (buttonIndex == UIAlertControllerBlocksCancelButtonIndex) {
NSLog(#"Cancel Tapped");
} else if (buttonIndex == UIAlertControllerBlocksDestructiveButtonIndex) {
NSLog(#"Delete Tapped");
} else if (buttonIndex >= UIAlertControllerBlocksFirstOtherButtonIndex) {
NSLog(#"Other Action Index %ld", (long)buttonIndex - UIAlertControllerBlocksFirstOtherButtonIndex);
}
}];
When I run it, I get this run-time error:
*** Terminating app due to uncaught exception 'NSGenericException', reason: 'Your application has presented a UIAlertController (<UIAlertController: 0x7fdfe3324f00>) of style UIAlertControllerStyleActionSheet. The modalPresentationStyle of a UIAlertController with this style is UIModalPresentationPopover. You must provide location information for this popover through the alert controller's popoverPresentationController. You must provide either a sourceView and sourceRect or a barButtonItem. If this information is not known when you present the alert controller, you may provide it in the UIPopoverPresentationControllerDelegate method -prepareForPopoverPresentation.'
What do I need to do to make this work? (I have looked at SO and Google and found nothing specific). I appreciate any help I can get on this...
UPDATE
I re-wrote it without the 3rd-party code; added this code, and now it works!
UIAlertController * view= [UIAlertController
alertControllerWithTitle:#"My Title"
message:#"Select your Choice"
preferredStyle:UIAlertControllerStyleActionSheet];
UIAlertAction* ok = [UIAlertAction
actionWithTitle:#"OK"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action)
{
//Do some thing here
[view dismissViewControllerAnimated:YES completion:nil];
}];
UIAlertAction* cancel = [UIAlertAction
actionWithTitle:#"Cancel"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action)
{
[view dismissViewControllerAnimated:YES completion:nil];
}];
[view addAction:ok];
[view addAction:cancel];
view.popoverPresentationController.sourceView = self.view;
view.popoverPresentationController.sourceRect = CGRectMake(self.view.bounds.size.width / 2.0, self.view.bounds.size.height / 2.0, 1.0, 1.0);
[self presentViewController: view animated:YES completion:nil];
The error message you received appeared because you ran iPhone code on an iPad. For use on an iPad, you have to set the alertController's popoverPresentationController. The source rectangle can be generated without the sloppy dimension calculations, too. Below, is a complete method, showing how you would encounter the code upon pressing a button. After setting up the AlertController the way you want, you get its popoverPresentationController and set it up for use with the iPad. In the method below, the button what was pressed is the sender. So we cast the sender back to that button, then use the button to set the rectangle. No messy dimensions need calculating. Now, if you run the code on the iPad, the popover will not display the Cancel button, (which does appear on the iPhone). That is by design. If you view the Apple UIPopoverController documentation, you see that the popover is cancelled by tapping outside of it.
- (IBAction)showImagePickerButtonTapped:(id)sender;
{
BOOL isCameraAvailable = [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera];
BOOL isPhotoLibraryAvailable = [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary];
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
[alertController addAction:[UIAlertAction actionWithTitle:#"Cancel" style:UIAlertActionStyleCancel handler:nil]];
if (isCameraAvailable) {
[alertController addAction:[UIAlertAction actionWithTitle:#"Camera" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
[self _showImagePickerWithSourceType:UIImagePickerControllerSourceTypeCamera];
}]];
}
if (isPhotoLibraryAvailable) {
[alertController addAction:[UIAlertAction actionWithTitle:#"Photo Library" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
[self _showImagePickerWithSourceType:UIImagePickerControllerSourceTypePhotoLibrary];
}]];
}
// The following lines are needed for use with the iPad.
UIPopoverPresentationController *alertPopoverPresentationController = alertController.popoverPresentationController;
UIButton *imagePickerButton = (UIButton*)sender;
alertPopoverPresentationController.sourceRect = imagePickerButton.frame;
alertPopoverPresentationController.sourceView = self.view;
[self showDetailViewController:alertController sender:sender];
}
There's precious little information to go on here...
It appears you're using https://github.com/ryanmaxwell/UIAlertController-Blocks, not the standard UIAlertController, in which case the exception suggests changes that the version of the code you're using doesn't cover yet or a use case that requires extra work on your part.
I've never used this 3rd-party code but a quick check doesn't show any obvious "do this" in the docs. My initial recommendation would be to implement the delegate method on the view in question and give it what it wants - the location at which to present the popover.

while UIAlertController is shown, parent's viewDidDisappear is not called (only on IOS8)

sadly i had to migrate from UIActionSheet to UIAlertController because IOS8 removed the first's functionality.
before using that, every time i went to and from home screen, the parent's view "viewDidDisappear" was called so i could dismiss the menu i've created.
now it's not called anymore.
the code looks like:
UIAlertController *alert = [UIAlertController .... preferredStyle:UIAlertControllerSTyleActionSheet]
UIAlertAction* a = [....]
[alert addAction: a];
alert.popoverPresentationController.barButtonItem = self.myButton // the bar button from my view
[self presentViewController:alert animated:YES completion:nil] // maybe im not showing the view well?
i have no idea how to continue from here.. would love some help
Thanks.
== EDIT ==
i saw that it happens also with the deprecated UIActionSheet and also with UIDcoumentInteractionController - ONLY in IOS8, not in IO7
Maybe I'm thinking too simple here, but wouldn't it be the easiest to put whatever code you had in a separate method and call that method from viewDidDisappear and after that bit of code you use to present that alert controller?
- (void)viewDidDisappear {
[self hideMenu];
}
- (void)hideMenu {
// Do all stuff to hide the menu you previously did in viewDidDisappear
}
And alter that presenting code like this
// more code here
[self presentViewController:alert animated:YES completion:nil];
[self hideMenu];

MFMailComposeViewController dismisses right away

The situation is the MFMailComposeViewController was going to be presented. I saw it was presented half-way done, but then it got dismissed.
This is the error:
_serviceViewControllerReady:error: Error Domain=_UIViewServiceInterfaceErrorDomain Code=3 "The operation couldn’t be completed. (_UIViewServiceInterfaceErrorDomain error 3.)"
This is my source code to present the MFMailComposeViewController:
-(void) MailExecute {
if ([MFMailComposeViewController canSendMail])
{
MFMailComposeViewController *mailViewController = [[MFMailComposeViewController alloc] init];
mailViewController.mailComposeDelegate = self;
[mailViewController setSubject:NSLocalizedString(#"Check this new look", #"")];
[mailViewController setMessageBody: #"my new look" isHTML:YES];
[self presentModalViewController:mailViewController animated:YES];
[mailViewController release];
}
else
{
UIAlertView *alertInternal = [[UIAlertView alloc]
initWithTitle: NSLocalizedString(#"Notification", #"")
message: NSLocalizedString(#"You have not configured your e-mail client.", #"")
delegate: nil
cancelButtonTitle:NSLocalizedString(#"OK", #"")
otherButtonTitles:nil];
[alertInternal show];
[alertInternal release];
}
}
The weird point is that sometimes it happens, sometimes it doesn't.
Please help me on this! I spend almost 1 working day to resolve this but no succeed.
This problem can occur when displaying a remote view controller -- a view controller run in another process -- as indicated by the UIViewService reference in the error message.
I've had this problem when displaying an SKStoreProductViewController, which is also a remote view controller. I'm not sure what the root cause is; the only thing that seemed to trigger it for me was presenting the view controller repeatedly.
For the SKStoreProductViewController I was able to check for this error in the completion block of the loadProductWithParameters:completionBlock: method. Does the MFMailComposeViewControllerDelegate give you a callback with an error about this? It may be that all you can do is listen for this error and show an error message to the user.
We should both probably file an apple radar about this.
Your code looks correct, and as stated the error message strongly suggests this has something to do with UIView proper (not MFMail specifically). The problem almost surely lies somewhere elsewhere within your code, and might be challenging to troubleshoot.
Some things to look for:
Other animations or view controller transitions/dismissals happening simultaneously or incorrectly (possibly like this)
Release/retain issues, of course
If none of that seems like the fix, try commenting-out everything else happening in the view controller that calls this method and see if it works then.
If you still can't get it working, present the simplest version you can of failing code so we can troubleshoot further. :)
Do you have anything in your viewDidDisappear: or viewWillDisappear methods that would dismiss a view controller?
If not, can you post more of your code for the ViewController that presents the MFMailComposeViewController?
I know this is the late reply, but may be help some other.
Just now face the same problem, By resetting the simulator work fine for me for this same issue. Let me know if this helps.
After I stored the MFMailComposeViewController in a strong property of my class instead of a local variable I could not reproduce the self-dismissing behaviour any more.
The issue for me was an incorrect argument when calling the attachment function. If you are having this issue with an email attachment I suggest following the solution found in this thread, as follows:
NSString *path = [self getDatabaseFilePath];
NSData *myData = [NSData dataWithContentsOfFile:path];
[picker addAttachmentData:myData mimeType:#"application/x-sqlite3" fileName:[path lastPathComponent]];
MFMailComposeViewController *mailComposer = [[MFMailComposeViewController alloc]init];
if ([MFMailComposeViewController canSendMail])
{
mailComposer.mailComposeDelegate = self;
[mailComposer setToRecipients:[NSArray arrayWithObject:#"support#kapsie.com"] ];
[mailComposer setSubject:#"Kapsie App Contact Support"];
[mailComposer setMessageBody:#"Type Your Feedback message here" isHTML:NO];
[self presentViewController:mailComposer animated:YES completion:nil];
}
Use above code and check it on device.
Use of modelViewController is deprecated in iOS 6 ,
use
[self presentViewController:mailView animated:YES completion:nil];
I face the same problem and the solution was:
I delete the overall application appearence related code like
[[UILabel appearance]setText:#""]
and replace with the code
[[UILabel appearanceWhenContainedIn:[self class], nil] setText:#""];
Now it is working fine so be carefull on overall application appearence changes: it might be navigationbar appearance, so and so