通过电子邮件发送的 NSDictionary 文件与应用程序中的相同文件不同

Posted

技术标签:

【中文标题】通过电子邮件发送的 NSDictionary 文件与应用程序中的相同文件不同【英文标题】:NSDictionary file emailed different than same file in app 【发布时间】:2014-04-11 14:50:40 【问题描述】:

在我的应用程序中,我在一个 NSDictionary 中存储了大约 6 个不同的键,并将该字典存储为一个文件,以便可以将其发送给应用程序的其他用户。我的三个键是我存储为字符串的数字:(例如)

 NSString *altitudeData = [NSString stringWithFormat:%1.50f",_altitude];
 [mutableDict setObject:altitudeData forKey:@"altitude"];
 [mutableDict writeToFile:filePath atomically:YES];

我将它与一些相关的媒体文件一起压缩并发送。

通常一切正常。应用程序接收压缩文件,解压缩它,读取 NSDictionary 文件(基本上是一个 XML)并根据它刚刚收到的信息创建一个对象。

但是,事情并不能始终如一地正常工作。这个问题让我特别困惑,因为我将相同的文件发送到我的应用程序和我的计算机。我以字符串形式存储的数字键(如我上面的示例)在我的应用读取的文件中更改为 0.00000……。

 <key>altitude</key>
 <string>0.00000000000000000000000000000000000000000000000000</string>

不过,我在计算机上将 NSDictionary 作为 XML 打开,我可以清楚地看到它们是正确的,就像我导出它们时一样。

 <key>altitude</key>
 <string>27.19356918334960937500000000000000000000000000000000</string>

我已经多次确认这些确实是同一个文件,其他一切都是一样的。我还尝试擦除我的应用程序并重新运行以确保我没有意外读取错误的文件。这些领域是如何以及为何发生转变的?有什么办法可以防止吗?

编辑:响应有关我如何压缩文件的请求 为此,我实际上正在使用从 github 导入的一些代码

     //first locate temp directory
     NSString *tmpDirectory = NSTemporaryDirectory();
     NSMutableString *fileNameOfZip = [NSMutableString stringWithFormat:@"%@.zip",_name];
     [fileNameOfZip replaceOccurrencesOfString:@" " withString:@"_" options:NSBackwardsSearch range:NSMakeRange(0, fileNameOfZip.length)];
     NSString *zipFilePath = [tmpDirectory stringByAppendingPathComponent:
                              fileNameOfZip];

     //then find all files related to zipping
     NSString *mainFilePath = [FILE_DIR stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.xml",_name]];
     NSString *imageFilePath = [self saveImages];
     NSString *videoFilePath = [self saveVideo];
     NSString *audioFilePath = [self saveAudio];
     NSMutableArray *filesToAdd = [[NSMutableArray alloc]initWithObjects: nil];
     [filesToAdd addObject:mainFilePath];
     [filesToAdd addObject:imageFilePath];
     [filesToAdd addObject:videoFilePath];
     [filesToAdd addObject:audioFilePath];
     ////HERE IS THE CLASS IMPORTED FROM github
     bool successful_zip = [SSZipArchive createZipFileAtPath:zipFilePath withFilesAtPaths:filesToAdd];

解压:

     NSData *fileAsData = [NSData dataWithContentsOfURL:file];
     NSString *urlAsString = file.absoluteString;
     NSArray *brokenFile = [urlAsString componentsSeparatedByString:@"/"];
     NSString *fileName = [brokenFile lastObject];
     NSString *buildPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"constructing"];
     createDirectory(buildPath);
     NSString *filePath = [buildPath stringByAppendingPathComponent:fileName];
     [fileAsData writeToFile:filePath atomically:NO];
     ////HERE IS THE CLASS IMPORTED FROM github
     bool upziped = [SSZipArchive unzipFileAtPath:filePath toDestination:buildPath];
     if (upziped) 
         NSLog(@"unzipped");
     
     else 
         NSLog(@"not unzipped");
     
     NSArray* buildDirectory = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:buildPath error:NULL];

     //import NSDictionary file
     ObjectItem *object = nil; /* This is the object I'm re-creating with my file*/
     for (NSString*s in buildDirectory) 
         NSLog(@"files here: %@",s);
         if ([s rangeOfString:@".xml"].location != NSNotFound) 
             NSString *name = [[s componentsSeparatedByString:@"."]firstObject];
             object = [ObjectItem retrieveFromName:name];
             break;
         
     

     //import image
     UIImage *image;
     for (NSString *media in buildDirectory) 
         if ([media rangeOfString:@".png"].location != NSNotFound) 
             NSString *imageFilePath = [buildPath stringByAppendingPathComponent:media];
             image = [[UIImage alloc]initWithContentsOfFile:imageFilePath];
             [object importImage:image];
             break;
         
     

     //import video
     for (NSString *media in buildDirectory) 
         if ([media rangeOfString:@".MOV"].location != NSNotFound) 
             NSString *videoFilePath = [buildPath stringByAppendingPathComponent:media];
             [object importVideo:videoFilePath];
             break;
         
     

     //import audio
     NSString *audioExt = [NSString stringWithFormat:@".%@",AUDIO_EXT];
     for (NSString *media in buildDirectory) 
         if ([media rangeOfString:audioExt].location != NSNotFound) 
             NSString *audioFilePath = [buildPath stringByAppendingPathComponent:media];
             [object importAudio:audioFilePath];
             break;
         
     

     [object save];

此外,这里的 [ObjectItem retrieveFromName] 方法也很有帮助

 +(ObjectItem
      *)retrieveFromName:(NSString*)name 
     NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
     NSString *documentsDirectory = [paths objectAtIndex:0];
     NSString *subDirectory = [documentsDirectory stringByAppendingPathComponent:@"ObjectItems"];
     createDirectory(subDirectory);
     NSString *filePath = [subDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.xml",name]];
     NSString *file = [NSString stringWithContentsOfFile:filePath encoding:NSASCIIStringEncoding error:nil];
     NSLog(@"file contents:\n%@\n",file);
     file = nil;
     NSDictionary *myDict = [NSDictionary dictionaryWithContentsOfFile:filePath];
     for (NSString *s in myDict) 
         NSLog(@"key \"%@\" has value: %@",s,[myDict objectForKey:s]);
     
     double lat = [[myDict objectForKey:@"latitude"]doubleValue];
     double lon = [[myDict objectForKey:@"longitude"]doubleValue];
     double alt = [[myDict objectForKey:@"altitude"]doubleValue];
     CLLocation *loc = [[CLLocation alloc]initWithCoordinate:CLLocationCoordinate2DMake(lat, lon)
                                                    altitude:alt
                                          horizontalAccuracy:kCLLocationAccuracyBestForNavigation
                                            verticalAccuracy:kCLLocationAccuracyBestForNavigation
                                                   timestamp:[NSDate date]];
     UIImage *im = nil;
     NSString *vid = nil;
     NSString *aud = nil;

     ObjectItem
       *object
       = [[ObjectItem
       alloc]initWithName:name location:loc];
     NSString *key = [myDict objectForKey:@"image"];
     if (key != nil) 
         im = [UIImage imageWithContentsOfFile:key];
         [object
       importImage:[im copy]];
     
     key = nil;
     key = [myDict objectForKey:@"video"];
     if (key != nil) 
         vid = [NSString stringWithString:key];
         [object
       importVideo:[vid copy]];
     
     key = nil;
     key = [myDict objectForKey:@"audio"];
     if (key != nil) 
         aud = [NSString stringWithString:key];
         [object
       importAudio:[aud copy]];
     
     paths = nil;
     documentsDirectory = subDirectory = filePath = nil;
     im = nil;
     vid = nil;
     aud = nil;
     myDict = nil;
     key = nil;
     return object
      ;
 

【问题讨论】:

旁注 - 为什么要小数点后 50 位? double 只适用于大约 13 或 14 位有效数字。 你是对的。我想这有点矫枉过正。我遇到了一些由于缺乏精度而导致的错误,我可能已经过度补偿了一点。 我们不知道您从哪里获得 _altitude。我们需要查看更多代码。 真的很重要吗?据我了解,这些值是正确写入的,正如在台式机上验证的那样。 @dev574,您 100 % 确定这些值是否正确写入?之后的变化对他们来说是相当神秘的。 除了说文件中的值不会自发改变之外,我没有看到任何帮助的方法。深入了解您所说的“我将其压缩并将其发送到我的应用程序”和“我将相同的文件发送到我的计算机”是什么意思。请用代码(和 NSLog 输出)重述这些句子 另一位评论者提示您发布不相关的代码。随意删除它。 (换句话说,请在发送前添加内容:here's NSLog output before I send. Here's how I zip and send,here's different log output on the receiver). 【参考方案1】:

我希望答案是深刻的,但不幸的是,原因是懒惰编程的结果。我的应用程序中有两个地方可以使用文件重新创建ObjectItem。在一个中,我正在根据文档文件夹中的信息重新创建对象,在另一个中,我正在根据临时信息中的信息重新创建。

我用来从文件重新创建对象的方法(我在上面有)+(ObjectItem*)retrieveFromName: 总是在 Document 文件夹中查找。当它在那里没有看到文件时,我的应用程序将重新创建我的ObjectItem,没有高度/坐标,并在 Document 文件夹中生成相应的文件。

【讨论】:

以上是关于通过电子邮件发送的 NSDictionary 文件与应用程序中的相同文件不同的主要内容,如果未能解决你的问题,请参考以下文章

如何通过填充 NSDictionary 以 JSON 格式发送 UIImage

为啥 NSJSONSerialization 将 NSDictionary 错误地解析为 JSON?

使用带有数组的 NSDictionary 创建 JSON 文件

通过过滤另一个 NSDictionary 来获取一个 NSDictionary

cron:将输出发送到文件,然后通过电子邮件将文件发送给我

使用phpmailer通过带有图像的html文件发送电子邮件