12

So I am creating a .csv file and then allowing the user to share it using the UIActivityViewController.

My code to create the csv file will return the NSURL of the file:

- (NSURL *)exportToCSV
{
    NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0];
    NSString *filePath = [docPath stringByAppendingPathComponent:@"results.csv"];

    if (![[NSFileManager defaultManager] fileExistsAtPath:docPath]) {
        [[NSFileManager defaultManager] createFileAtPath:filePath
                                                contents:nil
                                              attributes:nil];
    }

    NSMutableString *contents = [NSMutableString stringWithCapacity:0];

    //fill contents with data in csv format
    // ...

    NSFileHandle *fileHandle = [NSFileHandle fileHandleForUpdatingAtPath:filePath];
    [fileHandle writeData:[contents dataUsingEncoding:NSUTF8StringEncoding]];
    [fileHandle closeFile];

    return [NSURL fileURLWithPath:filePath];
}

and then my activity uses that NSURL to initiate the UIActivityViewController:

- (IBAction)shareButtonPressed:(id)sender {

    NSArray *activityItems = @[@"results.csv", [self.object exportToCSV]];
    UIActivityViewController *shareScreen = [[UIActivityViewController alloc] initWithActivityItems:activityItems applicationActivities:nil];

    [self presentViewController:shareScreen animated:YES completion:nil];
}

When I select mail an option, the csv file is not attached. it just has the text "results.csv"

what am I doing wrong?

Alex
  • 1,042
  • 3
  • 13
  • 32
  • 1
    Have you looked at the file? Is it ok? You can open the file on your simulator's folder (`~/Library/Application Support/iPhone Simulator/...`; you might have to hold the `option` key to see the `Library` folder in your Mac OS X Finder) and confirm that the file is ok. I generally would just save the string using `NSString` instance method `writeToFile`. Eliminates the `NSFileManager` and `NSFileHandle` stuff, too. – Rob Dec 16 '12 at 23:04
  • But in answer to your question, the problem would appear to be in your `fileExistsAtPath` line. You appear to be saying "if the documents directory doesn't exist, then create the file". You probably meant `filePath` there, not `docPath`. – Rob Dec 16 '12 at 23:18

3 Answers3

7

I want to share my solution of UIActivityViewController and sharing text as a CSV file. This solution works for sharing via Mail and even Save to Dropbox.

@IBAction func shareCsv(sender: AnyObject) {
    //Your CSV text
    let str = self.descriptionText.text!
    filename = getDocumentsDirectory().stringByAppendingPathComponent("file.csv")

    do {
        try str.writeToFile(filename!, atomically: true, encoding: NSUTF8StringEncoding)

        let fileData = NSURL(fileURLWithPath: filename!)

        let objectsToShare = [fileData]
        let activityVC = UIActivityViewController(activityItems: objectsToShare, applicationActivities: nil)

        self.presentViewController(activityVC, animated: true, completion: nil)

    } catch {
        print("cannot write file")
        // failed to write file – bad permissions, bad filename, missing permissions, or more likely it can't be converted to the encoding
    }

}

func getDocumentsDirectory() -> NSString {
    let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
    let documentsDirectory = paths[0]
    return documentsDirectory
}

Hope it helps! :)

Adam Studenic
  • 2,115
  • 2
  • 25
  • 22
6

The problem would appear to be in your fileExistsAtPath line. You appear to be saying "if the documents directory doesn't exist, then create the file". That's certainly not right.

Personally, I'd lose that stuff and change it to be

- (NSURL *)exportToCSV
{
    NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0];
    NSString *filePath = [docPath stringByAppendingPathComponent:@"results.csv"];

    NSMutableString *contents = [NSMutableString stringWithCapacity:0];

    //fill contents with data in csv format
    // ...

    NSError *error;

    [contents writeToFile:filePath
               atomically:YES
                 encoding:NSUTF8StringEncoding
                    error:&error];

    // check for the error

    return [NSURL fileURLWithPath:filePath];
}
Rob
  • 415,655
  • 72
  • 787
  • 1,044
5

This worked for me as a Swift 3 version, works as an attachment in Mail and saves in Dropbox.

var csvDetailsString = ""

for myObject in myObjectsArray {
    csvDetailsString = csvDetailsString.appending(myObject.someText)
    csvDetailsString = csvDetailsString.appending(",")
    csvDetailsString = csvDetailsString.appending("More Stuff")
    csvDetailsString = csvDetailsString.appending("\n")

}

let fileName = "Output"
let docDirectory = try? FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
if let fileURL = docDirectory?.appendingPathComponent(fileName).appendingPathExtension("csv") {
    do {
        try csvDetailsString.write(to: fileURL, atomically: true, encoding: .utf8)

        let objectsToShare = [fileURL]
        let activityVC = UIActivityViewController(activityItems: objectsToShare, applicationActivities: nil)

        activityVC.excludedActivityTypes = [UIActivityType.addToReadingList]
        self.present(activityVC, animated: true, completion: nil)

    } catch let error as NSError {
        print("Failed writing to URL: \(fileURL), Error: " + error.localizedDescription)
    }
}
Longmang
  • 1,663
  • 1
  • 13
  • 12