I have a camera application where the user can share the photos taken through email.
I am using MFMailComposerViewController to send mail. Here is the piece of code.
- (void) contactEmailRecepients:(NSArray *)emailIDs
subject:(NSString *)subject
attachment:(NSMutableDictionary *)attachmentDictionary
sender:(UIViewController *)sender
{
if ([MFMailComposeViewController canSendMail])
{
mailViewController = [[MFMailComposeViewController alloc] init];
mailViewController.mailComposeDelegate = self;
[mailViewController setToRecipients:emailIDs];
[mailViewController setSubject:subject];
NSData *attachmentData = [attachmentDictionary objectForKey:#"attachmentData"];
if (nil != attachmentData)
{
[mailViewController addAttachmentData:attachmentData
mimeType:[attachmentDictionary objectForKey:#"mimeType"]
fileName:[attachmentDictionary objectForKey:#"fileName"]];
}
[sender presentViewController:mailViewController
animated:YES
completion:^{}];
attachmentData = nil;
[attachmentDictionary removeAllObjects];
attachmentDictionary = nil;
}
else
{
// display error message
}
}
My problem is every time I send a mail through my application the VM(Virtual Memory) increases by 6/7 MB. But this does not happen if I comment out following part.
if (nil != attachmentData)
{
[mailViewController addAttachmentData:attachmentData
mimeType:[attachmentDictionary objectForKey:#"mimeType"]
fileName:[attachmentDictionary objectForKey:#"fileName"]];
}
The increased VM is due to CGRasterDataand the responsible library is CoreGraphicsand responsible caller is CGDataProvideCreateWithCopyOfDatawhen I check it through Xcode 5.0.2 instruments.So somewhere a copy is getting created which is not getting released later.I am suspecting the memory allocated to display the image in Email UIActionSheetis not getting released.
Any help is appreciated.
EDIT:
Adding the piece of code where attachmentData is getting initialized.
- (void)postPhotoFromPath:(NSString *)filePath
sender:(UIViewController *)sender
{
NSData *photoData = [NSData dataWithContentsOfFile:filePath];
if (nil == photoData)
{
//display error message
}
else
{
NSString *fileName = [[filePath componentsSeparatedByString:#"/"] lastObject];
[self contactEmailRecepients:nil
subject:nil
attachment:[NSDictionary dictionaryWithObjectsAndKeys:
photoData, #"attachmentData",
#"image/jpeg", #"mimeType",
fileName, #"fileName",
nil]
sender:sender];
}
}
Also I noticed carefully that VM increases exactly when i get the UIActionSheetregarding which image size to send(whether to send the original size or downscaled size). I am attaching the screenshot for the same here.
Related
I have simple text file generated in my application. The thing is I want to upload this text file on iCloud so that if the user installs app and inputs data he desires and then agin uninstalls this app. Then the next time he installs that app again I want to fetch the text file uploaded the first time he had used the same app.
I am facing a huge problem in integrating iCloud to my app.
I have done much research but didn't got any specific answers.
P.S. = I am not using Core data.
All i want is to upload the text file generated by the app into the iCloud Drive.
Please guide me step by step how can I achieve this. I have my developer account and I have a bit knowledge about the certificates and all. But still if anyone can please guide me how to achieve it.
I JUST WANT TO UPLOAD THE TEXT FILE TO ICLOUD AND RETRIEVE IT AGAIN WHEN THE SAME APP IS INSTALLED AGAIN (EVEN IF THE APP IS GETTING INSTALLED ON OTHER DEVICES).
ViewController.m
#pragma mark - Image Pick
- (IBAction)pickImage:(id)sender {
//select an image
UIImagePickerController *picker = [[UIImagePickerController alloc]init];
picker.delegate = self;
[self presentViewController:picker animated:YES completion:nil];
}
-(void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
[self dismissViewControllerAnimated:YES completion:nil];
}
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info
{
[self dismissViewControllerAnimated:YES completion:nil];
UIImage* image = [info objectForKey:UIImagePickerControllerOriginalImage];
self.imageView.image = image;
//SAVE IMAGE IN iCloud
AppDelegate* myAppDelegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
NSURL* cloudeImage = [myAppDelegate applicationCloudFolder:#"thePicture"];
NSData* imageDate = UIImagePNGRepresentation(image);
[imageDate writeToURL:cloudeImage atomically:YES];
}
-(void)populateUI
{
AppDelegate* myAppDelegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
NSURL* cloudeImageURL = [myAppDelegate applicationCloudFolder:#"thePicture"];
NSData* imageDate = [NSData dataWithContentsOfURL:cloudeImageURL];
UIImage* image = [UIImage imageWithData:imageDate];
if (image) {
self.imageView.image = image;
}
else
{
//download image from iCloud
NSLog(#"Downloading Image...");
[[NSFileManager defaultManager]startDownloadingUbiquitousItemAtURL:cloudeImageURL error:nil];
}
}
- (NSMetadataQuery *)query {
if (!_query) {
_query = [[NSMetadataQuery alloc]init];
NSArray *scopes = #[NSMetadataQueryUbiquitousDocumentsScope];
_query.searchScopes = scopes;
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"%K like %#", NSMetadataItemFSNameKey, #"*"];
_query.predicate = predicate;
if (![_query startQuery]) {
NSLog(#"Query didn't start... for whatever reason");
}
}
return _query;
}
AppDelegate.m
-(NSURL*)applicationCloudFolder:(NSString*)fileName
{
//TEAM ID AND CONTAINER ID
NSString* teamID = #"V58ESG9PLE";
NSString* bundelID =[NSBundle mainBundle].bundleIdentifier;
NSString* containerID = [NSString stringWithFormat:#"%#.%#",teamID,bundelID];
// URL to Cloud Folder
NSURL* cloudeRootURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:containerID];
NSLog(#"cloudeRootURL %#",cloudeRootURL);
NSURL* cloudDocuments = [cloudeRootURL URLByAppendingPathComponent:#"Document"];
//Apend our file name
cloudDocuments = [cloudDocuments URLByAppendingPathComponent:fileName];
return cloudDocuments;
}
Now I am not getting is my data being saved? ,Where is it getting saved? how can I retrieve it?
P.S. I am saving a picture
I have an APP to share people's photos to Mail, but on iPhone 6 Plus, I found it's preview image sometimes got cut, like this :
Image link is here:
Broken Image
In fact, there is a string like "Send from my phone" after image, it is cut too.
But if I move cursor to the end of the image, and press return on the keyboard, the image and "Send from my phone" become intactness.
I'm sorry, I can't send image directly,
here are the links:
Move Cursor
Here is my code:
- (void) shareToMailWithALAsset:(ALAsset *) asset {
if ([MFMailComposeViewController canSendMail]) {
NSString *imageName = asset.defaultRepresentation.filename;
MFMailComposeViewController *mailVC = [MFMailComposeViewController new];
mailVC.mailComposeDelegate = self;
[mailVC setMessageBody:"test"
isHTML:NO];
UIImage *image = [UIImage imageWithCGImage:asset.defaultRepresentation.fullScreenImage];
NSData *data = UIImageJPEGRepresentation(image, 1);
[mailVC addAttachmentData: data
mimeType:#"image/jpeg"
fileName:imageName];
[self presentViewController:mailVC
animated:YES
completion:nil];
}
else {
}
}
Any help will be appreciate. Thanks.
i want to add multiple passbook passes by running through a array with URLs. The problem is that the loop counts faster than the view controller can present.
Here s my code:
NSArray *passURLArray = [NSArray new];
passURLArray = response;
for (int i = 0; passURLArray.count; i++) {
NSString *passURLString = [NSString stringWithFormat:#"http://test.de%#", [passURLArray objectAtIndex:i]];
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:passURLString]];
NSError *error;
PKPass *pass = [[PKPass alloc] initWithData:data error:&error];
[[UIApplication sharedApplication] openURL:[pass passURL]];
PKAddPassesViewController *passVC = [[PKAddPassesViewController alloc] initWithPass:pass];
passVC.delegate = self;
[passVC setDelegate:(id)self];
[self presentViewController:passVC animated:YES completion:nil];
}
I get this error message:
Attempt to present PKAddPassesViewController: 0xca5f7d0 on
PaymentViewController: 0x14882290 which is waiting for a delayed
presention of PKAddPassesViewController: 0xb169470 to complete
Thanks in advance.
Check if you're on the last iteration of the loop. If you are, animate the display, if not, don't animate it.
That said, it's nasty from a user standpoint. You should probably think about a nicer way of presenting, like showing a list or animating between each display when addPassesViewControllerDidFinish: is called.
I am using PassSlot which creates a Pass on the fly that can be added to passbook. I am trying to get it downloaded to the device to allow attaching to an email. Here is what I have so far:
[PassSlot passFromTemplateWithName:#"LoveCouponCards" withValues:values pass:^(PSPass *pass) {
[PassSlot downloadPass:pass pass:^(PSPass *pass) {
PKPass *pkpass = [pass performSelector:#selector(pass)];
NSLog(#"Pass: %#", pkpass);
MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
picker.mailComposeDelegate = self;
NSArray *toRecipients = [NSArray arrayWithObject:#"friend#example.com"];
[picker setToRecipients:toRecipients];
[picker addAttachmentData:pkpass mimeType:#"application/vnd.apple.pkpass" fileName:#"HI"];
// Fill out the email body text
NSString *emailBody = \\
[picker setMessageBody:emailBody isHTML:NO];
[self presentViewController:picker animated:YES completion:nil];
}];
}];
The issue is that in the addAttachment part for the email, it throws an error that NSData can't relate to PKPass basically. How can I get pass converted to NSData so I can attach it?
UPDATE:
I tried doing
NSURL *url = pkpass.passURL;
NSData *so = [NSData dataWithContentsOfURL:url];
and then putting 'so' as the addAttachment, but it attached nothing to the email.
Firstly, the passURL property of PKPass doesn't quite work the way you think. It is not a URL to the pass itself. It is a URL that opens up the Passbook app and loads up that requested pass.
You can create a PKPass with NSData, but you can't reverse that process. It sounds as if you are trying to get a pass on device, and then e-mail it. That's not allowed - if it was, people could easily copy and distribute passes around (which isn't necessarily a good thing).
If you want to e-mail a user a pass you need to do it server, rather than client side. I'm afraid that what you're trying to do isn't possible using PassKit. Sorry!
Unfortunately the PassKit library does not provide a way to get back the NSData from a PKPass.
We already provide an API call that allows you to get the raw data of a pass.
We will extend our PassSlot SDK with a method that allows you to get the NSData without having the manually call this API method.
Update
The new SDK version 0.5 is now released. You can attach the pass with the following code:
[PassSlot passFromTemplateWithName:#"LoveCouponCards" withValues:values pass:^(PSPass *pass) {
[PassSlot downloadPass:pass pass:^(PSPass *pass) {
MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
picker.mailComposeDelegate = self;
[picker setToRecipients:#[#"friend#example.com"]];
[picker addAttachmentData:pass.data mimeType:#"application/vnd.apple.pkpass" fileName:#"LoveCouponCard.pkpass"];
[picker setMessageBody:emailBody isHTML:NO];
[self presentViewController:picker animated:YES completion:nil];
}];
}];
I'm facing a strange issue in my app and I need your help !
I am using a MFMailComposeViewController to send emails with attachment data. The attachment is either a PDF, a CSV or a XLS file. A ZIP file can also be added to the mail.
Everything works fine in most cases but sometimes (actually quite often), when the attachment is a XLS and a ZIP is added, I receive multiple memory warnings and the composer returns MFMailComposeResultFailed, with an error that doesn't help at all (only saying code error 1, "The operation couldn’t be completed. (MFMailComposeErrorDomain error 1.)").
My question is why does it do that ? I assume the memory warnings are telling me something is not well managed but I can't figure out what...
Here is my code for sending the email
-(void) sendMail {
MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
[self prepareMailPicker:picker];
NSString *filePath = [self getFilePath:pType];
NSString *zipFile = [self getZipPath];
NSString *mimeType;
int userPhoto = [User getCSVPhoto];
switch (pType) {
case EPDF:
mimeType = #"application/pdf";
userPhoto = [User getPDFPhoto];
break;
case ECSV:
mimeType = #"text/csv";
break;
case EExcel:
mimeType = #"application/vnd.ms-excel";
break;
default:
break;
}
NSData *attachmentData = [NSData dataWithContentsOfFile:filePath];
[picker addAttachmentData:attachmentData mimeType:mimeType fileName:[filePath lastPathComponent]];
if (userPhoto == 1 && shouldAddZip) {
NSData *zipData = [NSData dataWithContentsOfFile:zipFile];
[picker addAttachmentData:zipData mimeType:#"application/zip" fileName:[zipFile lastPathComponent]];
}
shouldAddZip = NO;
[self presentModalViewController:picker animated:YES];
}
-(void) prepareMailPicker:(MFMailComposeViewController*)picker {
picker.mailComposeDelegate = (id<MFMailComposeViewControllerDelegate>)self;
picker.navigationBar.tintColor = grayDark;
[picker setSubject:[TextManager textForKey:#"EMAIL_SUBJECT"]];
NSString *email = [[User currentUser] getEmail];
if (email && ![email isEqualToString:#""])
[picker setToRecipients:[NSArray arrayWithObject:email]];
NSString *emailBody = [TextManager textForKey:#"EMAIL_TEXT"];
[picker setMessageBody:emailBody isHTML:YES];
}
Any help would be grately apreciated !
EDIT: as asked by #matt, here is a log to prove that nothing is set to nil :
filePath : /var/mobile/Applications/A57F5CD2-E3FE-4417-8810-D746A22CF434/Documents/iNdF_Export_2012-11-19.xls
zipFile : /var/mobile/Applications/A57F5CD2-E3FE-4417-8810-D746A22CF434/Documents/iNdF_recus_2012-11-19.zip
attachmentData : (NSConcreteData *) <0x1d9c3c20> 53 874 bytes
zipData : (NSConcreteData *) <0x1f989100> 6 838 456 bytes
as you say, the problem seems most probably to do with memory management, given the memory warnings you are receiving.
your code is retaining a reference count to the attachmentData from the first file even as it goes out to get the zipData for the second file. internally, the picker is probably copying that data …
so the more you can do to release your references to large data as early as possible, the more likely you are not to get the memory warnings.
and if the problem is that the picker is unable to finish the attachment due to running out of memory, and you are able to get through it by doing early release, then breaking up the code in the following way may help you.
- (void)sendMailPicker:(MFMailComposeViewController*)picker addAttachmentUsingMimeType:(NSString*)mimeType {
NSString *filePath = [self getFilePath:pType];
NSData *attachmentData = [NSData dataWithContentsOfFile:filePath];
[picker addAttachmentData:attachmentData mimeType:mimeType fileName:[filePath lastPathComponent]];
}
- (void)sendMailAddPhotoUsingPicker:(MFMailComposeViewController*)picker {
NSString *zipFile = [self getZipPath];
NSData *zipData = [NSData dataWithContentsOfFile:zipFile];
[picker addAttachmentData:zipData mimeType:#"application/zip" fileName:[zipFile lastPathComponent]];
}
- (void)sendMail {
MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
[self prepareMailPicker:picker];
NSString *mimeType;
int userPhoto = [User getCSVPhoto];
switch (pType) {
case EPDF:
mimeType = #"application/pdf";
userPhoto = [User getPDFPhoto];
break;
case ECSV:
mimeType = #"text/csv";
break;
case EExcel:
mimeType = #"application/vnd.ms-excel";
break;
default:
break;
}
[self sendMailPicker:picker addAttachmentUsingMimeType:mimeType];
if (userPhoto == 1 && shouldAddZip) {
[self sendMailAddPhotoUsingPicker:picker];
}
shouldAddZip = NO;
[self presentModalViewController:picker animated:YES];
}
I guess that the problem is related to memory, when you create NSData you create in the heap. If it is to big you'll start to receive memory warnings. One way to avoid memory could be create a memory mapped NSData or an an NSStream but I have no idea on how to integrate a NSStream in mail composer. Which is the average size of your attachment?
You can also try to profile your app with Allocations to see wich is the memory footprint of your app, maybe is already too high.
like the some problems i had faced before.
1. Please check, there is internet availability using "Reachability" class file.
2. Please check your data size is within the limit.
3. Please check you configured your email id with your device.
you can also call [yourobj cansendmail] function to check whether it can send mail or not.