App crashes after exiting Mail Composer - email

My app is crashing shortly after closing a MFMailComposeViewController. A UIWebDocumentView is releasing, which deallocates a ComposeBodyField object and it crashes on objc_msgSend. It only happens some of the time, and only on old devices. I'm assuming that something is being release/cleaned up before it's supposed to, so when the message is sent, the object doesn't exist.
The problem is that I can't get anymore information than that, and I have no idea how any of it ties together. If anyone can shine some light on this, it would be great.

I've had similar problems with crashing after dimissing the MFMailComposer. After removing the [myMailComposer release] everything is fine. I'm sure I'm following the rules for memory management since it's fine all over in the app except at this specific place. Now my "Build & Analyze" nags about it, but the app is perfectly stable.

Please try this code that works for me.
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
{
switch (result)
{
case MFMailComposeResultCancelled:
{
break;
}
case MFMailComposeResultSaved:
{
break;
}
case MFMailComposeResultSent:
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Email" message:#"Email Sent" delegate:self cancelButtonTitle:#"OK" otherButtonTitles: nil];
[alert show];
[self performSegueWithIdentifier:#"backHome" sender: self];
break;
}
case MFMailComposeResultFailed:
{
NSLog(#" Failed");
break;
}
default:
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Email" message:#"Email Failed" delegate:self cancelButtonTitle:#"OK" otherButtonTitles: nil];
[alert show];
}
break;
}
}

Related

SKProductRequest doesn't fail without connection

I'd would like to handle the case in which in-app purchase products are requested without an internet connection.
When testing this case both in the simulator and a device (by turning off the wi-fi), instead of receiving a call to request:didFailWithError:, I receive a call productsRequest:didReceiveResponse: with an empty products array and then to requestDidFinish:.
Is this the expected behavior? If so, how can I know if the request failed due to a connection issue? If not, what might be wrong?
In case it helps, this is how I request the products:
- (void) requestProducts:(NSSet*)identifiers
{
_productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:identifiers];
_productsRequest.delegate = self;
[_productsRequest start];
}
I'm using iOS 6.
I don't know if its expected behavior because the docs are a little sparse on the subject. But I always do the checks myself so I can provide nice error messages to the user because it seems half the time the StoreKit Errors are very nondescript. Here is a bit of code I used in a recent project.
I have my own storeManager delegate to simplify calls and inheritance but it should be pretty clear whats happening.
#pragma mark - Purchase Methods
- (void)purchaseProduct:(SKProduct *)product
{
// Check Internet
if ([self checkInternetConnectionAndAlertUser:YES]) {
// Check Restrictions
if ([self checkRestrictionsAndAlertUser:YES]) {
// Check Products
if ([_products containsObject:product]) {
// Purchase the product
[[SKPaymentQueue defaultQueue] addPayment:[SKPayment paymentWithProduct:product]];
} else {
[[[UIAlertView alloc] initWithTitle:#"Error" message:#"Sorry, we couldn't find that product." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil] show];
[self.delegate purchaseDidFailWithError:[NSError errorWithDomain:#"SDInAppPurchaseManager" code:404 userInfo:#{ NSLocalizedDescriptionKey : #"Product not found." }]];
}
} else {
// Not allowed to make purchase
[self.delegate requestdidFailWithError:[NSError errorWithDomain:#"SDInAppPurchaseManager" code:500 userInfo:#{ NSLocalizedDescriptionKey : #"Not authorized to make purchases." }]];
}
} else {
// No Internet
[self.delegate requestdidFailWithError:[NSError errorWithDomain:#"SDInAppPurchaseManager" code:300 userInfo:#{ NSLocalizedDescriptionKey : #"No internet connection." }]];
}
}
#pragma mark - Checks
- (BOOL)checkInternetConnectionAndAlertUser:(BOOL)alert
{
if ([[SDDataManager dataManager] internetConnection]) {
return YES;
} else {
// Alert the user if necessary.
if (alert) {
[[[UIAlertView alloc] initWithTitle:#"No Connection" message:#"You don't appear to be connected to the internet. Please check your connection and try again." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil] show];
}
return NO;
}
}
- (BOOL)checkRestrictionsAndAlertUser:(BOOL)alert
{
if ([SKPaymentQueue canMakePayments]) {
return YES;
} else {
// Alert the user if necessary.
if (alert) {
[[[UIAlertView alloc] initWithTitle:#"Purchases Disabled" message:#"In App Purchasing is disabled for your device or account. Please check your settings and try again." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil] show];
}
return NO;
}
}

xcode webview error not working

This web view failed error showing the alert popup even when it is loading the website. I believe I need to delay this method in order for it to work.What will be the best method for doing this?
- (void)webView:(UIWebView *)webViewfail didFailLoadWithError:(NSError *)error
{
if([webViewfail isEqual:webview]) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Connection Failed" message:#"Check your Internet connection before refreshing."
delegate:webview
cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
}
}
Here is how I am loading the website
- (void)viewDidLoad
{
[webview loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.blabla.com"]]];
}
The problem is most likely an error -999 which generally happens when something from the webpage does not load correctly or a user tries to navigate back while the page is still loading. After some research here's what I found and used to keep the NetworkAlert from poping up every time but still popping up when there is no network.
-(void)webView:(UIWebView *)webBlog didFailLoadWithError:(NSError *)error{
if ([error code] != -999) {
NSLog(#"Could not load the dumb webPage");
//show error alert, etc.
[self showNoNetworkAlert];
}else{
NSLog(#"Could not load the dumb web page...just might blame user!");
}
}
- (void) showNoNetworkAlert{
UIAlertView *baseAlert = [[UIAlertView alloc]
initWithTitle:#"No Network" message:#"A network connection is required. Please verify your network settings and try again."
delegate:nil cancelButtonTitle:nil
otherButtonTitles:#"Dismiss", nil];
[baseAlert show];
}
Hope this helps someone...

locationManager didFailWithError Repeatedly Called

I am showing alertViews when Location manager unable to find current location. I did it like this
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
[manager stopUpdatingLocation];
switch([error code])
{
case kCLErrorNetwork: // general, network-related error
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Please check your network connection or that you are not in airplane mode" delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[alert show];
[alert release];
}
break;
case kCLErrorDenied:{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error" message:#"User has denied to use current Location " delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[alert show];
[alert release];
}
break;
default:
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Unknown network error" delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[alert show];
[alert release];
}
break;
}
}
My problem is locationManager didFailWithError method get called repeatedly. So my alertviews repeatedly display.
How can I solve this issue?
Apple documentation states:
If the location service is unable to retrieve a location right away,
it reports a kCLErrorLocationUnknown error and keeps trying. In such a
situation, you can simply ignore the error and wait for a new event.
If the user denies your application’s use of the location service,
this method reports a kCLErrorDenied error. Upon receiving such an
error, you should stop the location service.
So you might skip some cases where you stop updating and show the alert, especially the default case.
A good start for error messages that can be triggered by an ongoing background process - like the location manager - is to store the reference to the UIAlertView. When the delegate receives alertView:clickedButtonAtIndex:, reset this reference to nil. Before displaying new errors, check if one is already visible.
Even better, don't display modal error messages from background processes. Just walking around, you'll occasionally lose reception, and it's tedious to have to dismiss an error when that happens. If your app has a configuration or help screen, include a space there for the most recent error message from the Location Manager (or Game Center, or iCloud, or anything else that loses connectivity occasionally.)

Reachability False Positive

I'm getting false positives with my Reachability code. I get the UIAlert "No Internet Connection", when the network is available but not activated. Any help is very much appreciated.
//Check for Internet
Reachability* wifiReach = [[Reachability reachabilityWithHostName: #"www.apple.com"] retain];
NetworkStatus netStatus = [wifiReach currentReachabilityStatus];
switch (netStatus)
{
case NotReachable:
{
NSLog(#"Access Not Available");
break;
}
case ReachableViaWWAN:
{
NSLog(#"Reachable WWAN");
break;
}
case ReachableViaWiFi:
{
NSLog(#"Reachable WiFi");
break;
}
}
if (netStatus==NotReachable){
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Internet Required" message:#"There is no internet connection. Please connect and try again" delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[alert show];
[alert release];
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
}else{
//Push Controller
}
Same answer as the previous question.
Reachability sometimes only gives the correct answer after your app, or some previous app, has tried to connect and waited for data. So you might as well just try to get data from your connection, as that may well give you a more correct answer more quickly than asking the Reachability API. Maybe just let the user decide an activity indicator has been spinning long enough.

Getting some errors on UIAlertView

I have no idea why this is happening. It looks correct to me. I wrote another UIAlertView and it looked like it would be fine and as soon as I deleted this one it error-ed the one I wrote. I'm trying to follow this tutorial.
This is in my viewcontroller.m
- (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result
{
switch (result) {
case MessageComposeResultCancelled:
NSLog(#"Cancelled");
break;
case MessageComposeResultFailed:
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Welcome To My App" message:#"This app will ... First you need to ..." delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[alert show];
[alert release];
break;
case MessageComposeResultSent:
break;
default:
break;
}
[self dismissModalViewControllerAnimated:YES];
}
The errors are showing up on numerous lines of it such as: Missing "[" at start of message send expression. (If I have it put it in it wants to put another and another and another after initWithTitle:)
Next error is: Use of undeclared indentifier 'alert' (says this at the show and release)
Any idea what is going on? Thanks in advance.
Try adding brackets to your case statement that has multiple lines.
- (void)messageComposeViewController:(MFMessageComposeViewController
*)controller didFinishWithResult:(MessageComposeResult)result {
switch (result) {
case MessageComposeResultCancelled:
NSLog(#"Cancelled");
break;
case MessageComposeResultFailed: {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Welcome To My App" message:#"This app will ... First you need to ..." delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[alert show];
[alert release];
break;
}
case MessageComposeResultSent:
break;
default:
break; }
[self dismissModalViewControllerAnimated:YES]; }
why are You set the delegate, if you have not extra buttons in your Alert? I think, You should change delegate:self to delegate:nil.