This is for my iOS app using Core Data.
I'm getting some extra information in my CSV export that I'd like to remove. Below is my code and an example of what I am seeing.
Code:
NSOutputStream *stream = [[NSOutputStream alloc] initToMemory];
CHCSVWriter *writer = [[CHCSVWriter alloc] initWithOutputStream:stream encoding:NSUTF8StringEncoding delimiter:','];
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"Notes"];
self.fetchedObjects = [managedObjectContext executeFetchRequest:fetchRequest error:nil];
for (NSString *instance in self.fetchedObjects) {
[writer writeLineOfFields:#[instance.description]];
}
[writer closeStream];
NSData *buffer = [stream propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
NSString *output = [[NSString alloc] initWithData:buffer encoding:NSUTF8StringEncoding];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths firstObject];
NSString * csvPath = [documentsDirectory stringByAppendingPathComponent:#"mydata.csv"];
if ([MFMailComposeViewController canSendMail]) {
MFMailComposeViewController * mailView = [[MFMailComposeViewController alloc] init];
mailView.mailComposeDelegate = self;
[[mailView navigationBar] setTintColor:[UIColor whiteColor]];
[mailView setSubject:#"My Subject Line"];
if (![[NSFileManager defaultManager] fileExistsAtPath:csvPath]) {
[[NSFileManager defaultManager] createFileAtPath:csvPath contents:nil attributes:nil];
}
BOOL res = [[output dataUsingEncoding:NSUTF8StringEncoding] writeToFile:csvPath atomically:NO];
if (!res) {
[[[UIAlertView alloc] initWithTitle:#"Error Creating CSV" message:#"Check your permissions to make sure this app can create files so you may email the app data" delegate:nil cancelButtonTitle:#"Okay" otherButtonTitles: nil] show];
} else{
NSLog(#"Data saved! File path = %#", csvPath);
[mailView addAttachmentData:[NSData dataWithContentsOfFile:csvPath] mimeType:#"text/csv" fileName:#"mydata.csv"];
[self presentViewController:mailView animated:YES completion:nil];
}
} else {
UIAlertView * alertView = [[UIAlertView alloc] initWithTitle:#"Mail Error" message:#"Your device is not configured to send mail." delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
}
Output Example:
<Notes: 0x1c009fb30> (entity: Notes; id: 0xd000000000080000 <x-coredata://597EDC54-FFDE-43FA-8C61-DE67763C1D13/Notes/p2> ; data: {
// My data shows here.
})
What I want:
I just want the saved data from the user input. Not the extra data about the entity, id, etc.
Also:
My data does not load in the email initially. I have to go into my UIViewController and then when I go to my Settings page and send the email the data shows. What would cause this?
You're getting that result because you're relying the description method to get information about your objects. That method produces a string, and the string is what you're seeing-- something that's not CSV, or easy to convert to CSV.
I'm not familiar with CHCSVParser but it looks like you might want to override description in your Notes class to produce something that CHCSVParser can handle. The default implementation on NSManagedObject-- which is what you're using now-- is not a good choice for this situation.
Related
I have a requirement of downloading .zip file from server and use it to project after extracting it. I have successfully downloaded the .sqlite file and i am able to extract it using right click(manually) but when i am trying to extract it using minizip and SSZipArchive or ZipArchive it's giving an error "Can't open the file".
If i extract .sqlite manually and compress .sqlite file by right clicking in mac then my code is extracting it completely but whenever i try to extract downloaded file directly then this issue is occurring.
I have applied below name formats for writing and extracting file.
While writing file the name was XYZ.sqlite.zip but it is also giving error
XYZ.zip and contained file name is XYZ.sqlite. This also giving error
I also have written file with name XYZ.sqlite.zip and then rename it with XYZ.zip and then extracted but that was also not working.
Below is the code.
For Downloading the file:
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:zipURL]];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [[paths objectAtIndex:0] stringByAppendingPathComponent:[zipURL lastPathComponent]];
operation = [[AFDownloadRequestOperation alloc] initWithRequest:request targetPath:path shouldResume:YES];
[operation.securityPolicy setAllowInvalidCertificates:YES];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
[self unzipDBFile:path];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
[operation setProgressiveDownloadProgressBlock:
^(AFDownloadRequestOperation *operation, NSInteger bytesRead, long long totalBytesRead, long long totalBytesExpected, long long totalBytesReadForFile, long long totalBytesExpectedToReadForFile) {
NSArray *progress = [NSArray arrayWithObjects:obj_Pro,[NSNumber numberWithFloat:totalBytesReadForFile/(float)totalBytesExpectedToReadForFile], nil];
[self performSelectorOnMainThread:#selector(updateProgressBar:) withObject:progress waitUntilDone:NO];
}];
[operation start];
For Extracting the file:
-(void)unzipDBFile:(NSString *)filePath
{
NSString *documentDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES) objectAtIndex:0];
NSString *outputPath = [documentDir stringByAppendingPathComponent:#"/DBFolder"];
BOOL isExtracted =[SSZipArchive unzipFileAtPath:outputPath toDestination:documentDir];
// NSString *filepath = [[NSBundle mainBundle] pathForResource:#"ZipFileName" ofType:#"zip"];
// ZipArchive *zipArchive = [[ZipArchive alloc] init];
// [zipArchive UnzipOpenFile:filePath];
// NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
// NSString *path = [paths objectAtIndex:0];
// BOOL isExtracted=[zipArchive UnzipFileTo:path overWrite:YES];
// NSLog(#"PATH=%#",path);
if (!isExtracted)
{
UIAlertView *alert=[[UIAlertView alloc] initWithTitle:#"Error in extracting" message:#"" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alert show];
[alert release];
}else{
UIAlertView *alert=[[UIAlertView alloc] initWithTitle:#"Extract Success" message:#"" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alert show];
[alert release];
}
// [zipArchive UnzipCloseFile];
// [zipArchive release];
}
Below is the code for update progressbar:
- (void)updateProgressBar:(NSArray *)progress
{
UIProgressView *pgr = (UIProgressView *)[progress objectAtIndex:0];
[pgr setProgress:[[progress objectAtIndex:1] floatValue]];
}
I have examined the issue and found that .net developer, Who created .zip has used gzip compression so minizip is not able to extract it.
For decompress it, I have used iOS zlib framework and below code and that has solved my problem. You have to add below two things in the header before implementing this method.
#import <zlib.h>
#define CHUNK 16384
-(BOOL)unzipDBFile:(NSString *)filePath
{
NSString *documentDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES) objectAtIndex:0];
documentDir=[documentDir stringByAppendingPathComponent:DATABASE_FILE_NAME];
gzFile file = gzopen([filePath UTF8String], "rb");
FILE *dest = fopen([documentDir UTF8String], "w");
unsigned char buffer[CHUNK];
int uncompressedLength;
while ((uncompressedLength = gzread(file, buffer, CHUNK)) ) {
// got data out of our file
if(fwrite(buffer, 1, uncompressedLength, dest) != uncompressedLength || ferror(dest)) {
return FALSE;
}
}
fclose(dest);
gzclose(file);
return TRUE;
}
I have made a pdf file and I am trying to attach it with the email but the file doesn't get attached infact the file name isn't what, what it is suppose to be. Following is my code
- (IBAction)btnAttachPDF:(id)sender {
if ([MFMailComposeViewController canSendMail])
{
MFMailComposeViewController *mailer = [[MFMailComposeViewController alloc] init];
mailer.mailComposeDelegate = self;
[mailer setSubject:#"video"];
NSArray *toRecipients = [NSArray arrayWithObjects:#"", nil];
[mailer setToRecipients:toRecipients];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *fileName;
fileName = [[NSString alloc]initWithFormat:#"%#.pdf", lblName.text];
lblName.text suppose to returns me the file name which i have entered but it is just .pdf but if I give it a hardcoded value it does stores the name of the file lets say I gave it a name #"rio.pdf" but later on the file doesn't get attached.
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *pdfFileName = [documentsDirectory stringByAppendingPathComponent:fileName];
NSMutableData *myPdfData = [NSMutableData dataWithContentsOfFile:pdfFileName];
[mailer addAttachmentData:myPdfData mimeType:#"application/pdf" fileName:fileName];
[self presentViewController:mailer animated:YES completion:nil];
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Failure"
message:#"Your device doesn't support the composer sheet"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
}
Actually the path returned by NSSearchPathForDirectoriesInDomains isn't the exact one. The last component it was returning was /Documents whereas, the files were being saved in /Documents/temp/filename.pdf
I can send a .csv file as an attachment from my app, but I'd like to shorten the name file for that attachment, because there will be a pile of csv files delivered to the recipient.
Piece of code:
...
if (dorsalesPorTramoYcontrol && dorsalesPorTramoYcontrol.count )
{
NSMutableString *mainString = [[ NSMutableString alloc]initWithString:#"dorsal,paso,tiempo\n"];
for (NSManagedObject *get in dorsalesPorTramoYcontrol) {
//dorsales
NSString *string =[get valueForKey:#"dorsal"];
[mainString appendFormat:#"%#,",string];
//paso
string = [get valueForKey:#"paso"];
string=[string stringByReplacingOccurrencesOfString:#"\"" withString:#"\"\""];
[mainString appendFormat:#"%#,",string];
//tiempo
string = [get valueForKey:#"tiempo"];
string=[string stringByReplacingOccurrencesOfString:#"\"" withString:#"\"\""];
[mainString appendFormat:#"%#",string];
[mainString appendFormat:#"\n"];
}
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectoryPath = [paths objectAtIndex:0];
file = [NSString stringWithFormat:#"%#/Tramo%#Control%#.csv", documentsDirectoryPath,section,control];
NSError *csVerror= NULL;
BOOL written = [mainString writeToFile:file atomically:YES encoding:NSUTF8StringEncoding error:&csVerror];
if (!written) {
NSLog( #"Writing failed, error = %#",csVerror);
}else {
NSLog(#"Data saved! File path = %#",file);
[self composeEmail];
}
}
}
-(void)composeEmail{
if ([MFMailComposeViewController canSendMail])
{
MFMailComposeViewController *mailer = [[MFMailComposeViewController alloc] init];
mailer.mailComposeDelegate = self;
[mailer setSubject:[NSString stringWithFormat:#"Resultados Tramo: %# - Control: %#", section, control]];
NSArray *toRecipients = [NSArray arrayWithObjects:#"somebodymail#mail.com", nil];
[mailer setToRecipients:toRecipients];
// Logo
UIImage *myImage = [UIImage imageNamed:#"logo.png"];
NSData *imageData = UIImagePNGRepresentation(myImage);
[mailer addAttachmentData:imageData mimeType:#"image/png" fileName:#"Icon"];
[mailer addAttachmentData:[NSData dataWithContentsOfFile:file] mimeType:#"text/csv" fileName:file];
NSString *emailBody =
[NSString stringWithFormat:#"Resultados Tramo: %# - Control: %# \nDorsal - Paso - Tiempo", section, control];
[mailer setMessageBody:emailBody isHTML:NO];
mailer.modalPresentationStyle = UIModalPresentationPageSheet;
[self presentViewController:mailer animated:YES completion:nil];
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Failure"
message:#"Your device doesn't support the composer sheet"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles: nil];
[alert show];
}
}
The filename is the following:
<_var_mobile_Applications_BE8CE610-A83E-4C79-8B9C-0263FA6881D6_Documents_Tramo2Control4.csv>
and I'd like it to be just "Tramo2Control4.csv"
Could you please offer some suggestions to get it?
Change the following line:
[mailer addAttachmentData:[NSData dataWithContentsOfFile:file] mimeType:#"text/csv" fileName:file];
To:
NSString *fileName = [file lastPathComponent];
[mailer addAttachmentData:[NSData dataWithContentsOfFile:file] mimeType:#"text/csv" fileName:fileName];
You were originally setting the file name to be the entire file path.
I would like to create a file using a NSString (already made) with a .csv extension then email it using the UIMessage framework. So can someone show me the code to create a file (with a .csv extensions and with the contents of a NSString) then how to attach it to a MFMailComposeViewController.
This is how you attach a CSV file to a MFMailComposeViewController:
MFMailComposeViewController *mailer = [[MFMailComposeViewController alloc] init];
mailer.mailComposeDelegate = self;
[mailer setSubject:#"CSV File"];
[mailer addAttachmentData:[NSData dataWithContentsOfFile:#"PathToFile.csv"]
mimeType:#"text/csv"
fileName:#"FileName.csv"];
[self presentModalViewController:mailer animated:YES];
// Note: PathToFile.csv is the actual path of the file on your iOS device's
// file system. FileName.csv is what it should be displayed as in the email.
As far as how to generate the CSV file itself, the CHCSVWriter class at https://github.com/davedelong/CHCSVParser will help you.
Here are the parts where you create a new csv, save it to file and attach it all in one. You know, if you're in to that sort of thing
NSString *emailTitle = #"My Email Title";
NSString *messageBody = #"Email Body";
MFMailComposeViewController *mc = [[MFMailComposeViewController alloc] init];
mc.mailComposeDelegate = self;
[mc setSubject:emailTitle];
[mc setMessageBody:messageBody isHTML:NO];
[mc setToRecipients:#[]];
NSMutableString *csv = [NSMutableString stringWithString:#""];
//add your content to the csv
[csv appendFormat:#"MY DATA YADA YADA"];
NSString* filePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString* fileName = #"MyCSVFileName.csv";
NSString* fileAtPath = [filePath stringByAppendingPathComponent:fileName];
if (![[NSFileManager defaultManager] fileExistsAtPath:fileAtPath]) {
[[NSFileManager defaultManager] createFileAtPath:fileAtPath contents:nil attributes:nil];
}
BOOL res = [[csv dataUsingEncoding:NSUTF8StringEncoding] writeToFile:fileAtPath atomically:NO];
if (!res) {
[[[UIAlertView alloc] initWithTitle:#"Error Creating CSV" message:#"Check your permissions to make sure this app can create files so you may email the app data" delegate:nil cancelButtonTitle:#"Okay" otherButtonTitles: nil] show];
}else{
NSLog(#"Data saved! File path = %#", fileName);
[mc addAttachmentData:[NSData dataWithContentsOfFile:fileAtPath]
mimeType:#"text/csv"
fileName:#"MyCSVFileName.csv"];
[self presentViewController:mc animated:YES completion:nil];
}
I found a code snippet here, which I wanted to use, but I can't figure out how to make it back "to string" and see if it works...
// some strings for test
NSString *cpu = [[NSString alloc] initWithFormat:#"%.0f", [_cpuSlider value]];
NSString *ram = [[NSString alloc] initWithFormat:#"%.0f", [_ramSlider value]];
NSString *hdd = [[NSString alloc] initWithFormat:#"%.0f", [_hddSlider value]];
// put them into dictionary
NSDictionary *test = [NSDictionary dictionaryWithObjectsAndKeys:cpu, #"CPU", ram, #"RAM", hdd, #"HDD", nil];
// start of the code from page above
NSMutableData *myData = [[NSMutableData alloc]init];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc]initForWritingWithMutableData:myData];
[archiver encodeObject:test forKey:#"MyKEY"];
[archiver finishEncoding];
id testJson = [NSJSONSerialization JSONObjectWithData:myData options:0 error:nil];
// end of code
// HERE I'd like know what to put in to see it as a string..e.g. { "CPU"=value; etc...}
UIAlertView *av = [[UIAlertView alloc] initWithTitle:#"MLIA" message:????? delegate:nil cancelButtonTitle:#"Zavřít" otherButtonTitles: nil];
[av show];
Thanks a lot!
NSKeyedArchiver doesn't produce JSON (AFAIK), so I don't know how that linked example could possibly work. If you want to JSON-encode a dictionary, you would use +dataWithJSONObject:options:error::
NSError *err;
NSData *json = [NSJSONSerialization dataWithJSONObject:test options:0 error:&err];
NSAssert1(json, #"Error: %#", err);
// If not using ARC, remember to (auto)release repr.
NSString *repr = [[NSString alloc] initWithData:json encoding:NSUTF8StringEncoding];
[[UIAlertView …] … message:repr …];