电子邮件附件不起作用,因为文件尚未完成保存?

时间:2015-10-23 15:33:03

标签: ios objective-c

我有一个函数可以将从本地SQLite DB中提取的数据保存到.CSV文件中。

我的问题是,此功能还会触发另一个将文件附加到电子邮件并发送的功能。由于文件尚未完成保存,附件将作为空文件发送。

无论如何我可以在将文件附加到电子邮件之前检查文件是否已完成保存?请参阅下面的功能:

    // When the tick is visible within the animation...
        // Play the bellToneSound.
        AudioServicesPlaySystemSound(bellToneSound);
        // Creates a temporary GPS object that we will use to save our database as a .CSV file.
        GPS *saveGPS = [[GPS alloc] init];
        // Finds the phone's documents directory and creates a file path in order create a new file/folder there.
        NSError *error = nil;
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *documentsDirectory = [paths objectAtIndex:0];
        NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:@"/Jobs"];
        if (![[NSFileManager defaultManager] fileExistsAtPath:dataPath]){
            [[NSFileManager defaultManager] createDirectoryAtPath:dataPath withIntermediateDirectories:NO attributes:nil error:&error];
        }
        NSString *filePath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"/Jobs/%@.csv", proposalNumber]];
        // Creates our new file, with a name matching "jobNo.csv" overrites old one if it already exists.
        [[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil];
        // Creates a file handler which will allow us to write to our file.
        NSFileHandle *myHandle = [NSFileHandle fileHandleForWritingAtPath:filePath];
        // Creates and writes the first line to our CSV file, which tells the program reading it what the column titles are.
        NSString *csvTitleString =@"Source/Monitor, Latitude, Longitude";
        [myHandle writeData:[csvTitleString dataUsingEncoding:NSUTF8StringEncoding]];
        // Creates initializes another string object which will hold each line we want to write.
        NSString *csvString = [[NSString alloc] init];
        // Declares an array and fills it with all GPS objects found in our Database.
        NSArray *allGPS = [[NSArray alloc]initWithArray:[database getAll]];
        // While the current index value is less than the length of the array write the GPS values into our file then take a new line.
        for(int i=0;i<(allGPS.count);i++){
            saveGPS = [allGPS objectAtIndex:i];
            csvString = [NSString stringWithFormat:@"\n %@ %d, %@, %@", [saveGPS sourceMonitor], [[saveGPS positionNo] intValue], [saveGPS latitude], [saveGPS longitude]];
            [myHandle seekToEndOfFile];
            [myHandle writeData:[csvString dataUsingEncoding:NSUTF8StringEncoding]];
        }
}

更新

以下是您要求的代码。

NSString *docsDir;
NSString *realpath;
NSArray *dirPaths;
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = dirPaths[0];
realpath=[[NSString alloc] initWithString:[docsDir stringByAppendingPathComponent: [NSString stringWithFormat:@"/Jobs/temp.csv"]]];
NSFileManager *filemgr = [NSFileManager defaultManager];
if ([filemgr fileExistsAtPath: realpath ] == YES)
{
    [self checkIfSaved];
}
else
{
    NSLog(@"file found");
    // Checks if the device can send email.
    if([MFMailComposeViewController canSendMail]){
        // Sets the subject to data from (our current proposal number).
        [mail setSubject:[NSString stringWithFormat:@"Data from %@", proposalNumber]];
        [mail setMessageBody:@"Please see the attached .CSV file." isHTML:NO];
        // Finds the .CSV file we just saved, and attaches it to the email.
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *documentsDirectory = [paths objectAtIndex:0];
        NSString *filePath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"/Jobs/%@.csv", proposalNumber]];
        NSData *attachment = [NSData dataWithContentsOfFile:[NSString stringWithFormat:@"%@", filePath]];
        [mail addAttachmentData:attachment mimeType:@"text/csv" fileName:[NSString stringWithFormat:@"%@",proposalNumber]];
        // Opens up the email screen.
        [self presentViewController:mail animated:YES completion:NULL];
    }
    else
    {
        // Tells the user that there device cannot send email.
        NSLog(@"This device cannot send email");
        // Creates a popup window to inform the user that their location wasn't updates.
        UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Error"
                                                                       message:@"Unable to send email. Have you set up a mail account on this device?"
                                                                preferredStyle:UIAlertControllerStyleAlert];
        UIAlertAction* dismissAction = [UIAlertAction actionWithTitle:@"Dismiss" style:UIAlertActionStyleCancel handler:^(UIAlertAction * action) {}];
        alert.view.tintColor = [UIColor orangeColor];
        [alert addAction:dismissAction];
        [self presentViewController:alert animated:YES completion:nil];
    }
}

1 个答案:

答案 0 :(得分:1)

您需要安排代码,以便电子邮件部分在文件完全保存之后才会启动。有很多方法可以做到这一点:

  • 轮询:您可以继续检查文件的状态,直到您发现操作完成为止。有时轮询是不可避免的,但它通常是最糟糕的选择。不要走这条路。

  • 完成例程:文件保存方法可以采用一个参数,该参数是保存完成时要执行的代码块。这很常见,您可以在各种iOS框架中看到它。例如,NSURLSession有一个-dataTaskWithURL:completionHandler:方法。加载请求的数据后,将调用完成处理程序。

  • 串行执行:将文件保存代码放在一个块中,将邮件发送到另一个块中。然后您可以使用NSOperationQueue或直接使用Grand Central Dispatch来调度串行队列中的两个块,以便第二个块在第一个块完成之前不会启动。

完成例程方法和串行执行方法都是合理的方法,可确保您在保存文件之前不启动电子邮件过程,因此请选择最适合您的方式。