MFMailComposeViewController problem
This problem is probably not specific to MFMailComposeViewController, but that is where I am having the problem...
I am building the NSString "myEmailString" for the messageBody of the MFMailComposeViewController and storing it in an iVar before displaying the MFMailComposeViewController as a modal view controller.
I pass the string into the MFMailComposeViewController, then present it as a modal view controller.
When the modal view controller is dismissed, my iVar becomes invalid,
and the app crashes when I release the emailString iVar in dealloc
Code below, what am I doing wrong?
-(void)buildEmailMessage {
int mySection;
int myRow;
NSString *buildString = [NSString stringWithFormat:@"<b><p>Ten Essentials Check List</b><br />%@</p>", [myList valueForKey:@"listName"]];
for (mySection = 0; mySection < [[fetchedResultsController sections] count]; mySection ++) {
NSString *sectionName = [NSString stringWithFormat:@"<p><b>%@ Group</b></p><ul>", [[[fetchedResultsController sections] objectAtIndex:mySection] name]];
buildString = [buildString stringByAppendingString:sectionName];
id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:mySection];
for (myRow = 0; myRow < [sectionInfo numberOfObjects]; myRow ++) {
// Get the managedObject
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:myRow inSection:mySection];
NSManagedObject *managedObject = [fetchedResultsController objectAtIndexPath:indexPath];
//Get the related Item object
Item *item = [managedObject valueForKey:@"item"];
NSString *itemName = [NSString stringWithFormat:@"<li>%@</li>", item.itemName];
buildString = [buildString stringByAppendingString:itemName];
}
buildString = [buildString stringByAppendingString:@"</ul>"];
}
myEmailString = [NSString stringWithString:buildString];
NSLog(@"email string = :\n%@", myEmailString);
[self showPicker];
}
#pragma mark -
#pragma mark Send Mail
-(void)showPicker {
// This code can run on devices running iPhone OS 2.0 or later
// The MFMailComposeViewController class is only available in iPhone OS 3.0 or later.
// So, we must verify the existence of the above class and provide a workaround for devices running
// earlier versions of the iPhone OS.
// We display an email composition interface if MFMailComposeViewController exists and the devi开发者_Go百科ce can send emails.
// We launch the Mail application on the device, otherwise.
NSLog(@"Checking OS for MFMailComposeViewController");
Class mailClass = (NSClassFromString(@"MFMailComposeViewController"));
if (mailClass != nil)
{
// We must always check whether the current device is configured for sending emails
if ([mailClass canSendMail])
{
[self displayComposerSheet];
}
else
{
[self launchMailAppOnDevice];
}
}
else
{
[self launchMailAppOnDevice];
}
}
// Displays an email composition interface inside the application. Populates all the Mail fields.
-(void)displayComposerSheet {
MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
picker.mailComposeDelegate = self;
picker.navigationBar.barStyle = UIBarStyleBlack;
[picker setSubject:@"Here is your gear check list!"];
// Attach an image to the email
NSString *path = [[NSBundle mainBundle] pathForResource:@"Checkmark_icon" ofType:@"png"];
NSData *myData = [NSData dataWithContentsOfFile:path];
[picker addAttachmentData:myData mimeType:@"image/png" fileName:@"Checkmark_icon"];
// Fill out the email body text
//***** NOTE: This is where I pass the value from my iVar *****
// into the MFMailComposeViewController
//
NSString *emailBody = [NSString stringWithString:myEmailString];
[picker setMessageBody:emailBody isHTML:YES];
NSLog (@"DIsplaying Composer Sheet");
[self presentModalViewController:picker animated:YES];
[picker release];
}
// Dismisses the email composition interface when users tap Cancel or Send. Proceeds to update the message field with the result of the operation.
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error {
//message.hidden = NO;
// Notifies users about errors associated with the interface
switch (result)
{
case MFMailComposeResultCancelled:
NSLog (@"Result: canceled");
break;
case MFMailComposeResultSaved:
NSLog (@"Result: saved");
break;
case MFMailComposeResultSent:
NSLog (@"Result: sent");
break;
case MFMailComposeResultFailed:
NSLog (@"Result: failed");
break;
default:
NSLog (@"Result: not sent");
break;
}
[self dismissModalViewControllerAnimated:YES];
// ***** NOTE: Line below was added to fix the invalid iVar problem *****
myEmailString = @"";
}
#pragma mark -
#pragma mark Workaround
// Launches the Mail application on the device.
-(void)launchMailAppOnDevice {
NSString *recipients = @"mailto:first@example.com?cc=second@example.com,third@example.com&subject=Here is your gear check list!";
NSString *body = myEmailString;
NSString *email = [NSString stringWithFormat:@"%@%@", recipients, body];
email = [email stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:email]];
}
- (void)dealloc {
[managedObjectContext release];
[fetchedResultsController release];
[tableview release];
[myList release];
[myEmailString release];
[super dealloc];
}
how is your ivar declared? is it declared as a property? in any case, it is not automatically retained for you.
Either you need to do
myEmailString = [[NSString stringWithString:buildString] retain];
or
self.myEmailString = [NSString stringWithString:buildString];
if you have myEmailString declared as
@property (nonatomic, retain) NSString *myEmailString
Think about it: if all ivars were automatically retained for you, then how would you have a variable that you didn't want to retain? That's why it doesn't work that way.
when you are creating the myEmail string in buildEmailMessage you are never retaining the string. Thus after leaving the function it is autoreleased. Your retain count then when dealloc is called will be 0, which will cause the crash. If you want to keep the variable you will need to have the line as follows
myEmailString = [[NSString stringWithString:buildString] retain];
then you can call [myEmailString release]
safely
stringWithString:
creates a new string and autoreleases it before returning it to you. Unless you retain the returned string, you don't need to release it in your dealloc method.
You should be retaining your string before storing it in your iVar:
myEmailString = [[NSString stringWithString:buildString] retain];
It becomes invalid without this due to it being autoreleased later during the execution of your program. This will also ensure it's still allocated when your destructor is called, preventing release crashing.
精彩评论