Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/cocoa/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Cocoa touch 如何防止此NSPropertyListSerialization崩溃?_Cocoa Touch_Cocoa - Fatal编程技术网

Cocoa touch 如何防止此NSPropertyListSerialization崩溃?

Cocoa touch 如何防止此NSPropertyListSerialization崩溃?,cocoa-touch,cocoa,Cocoa Touch,Cocoa,我有一个适用于Mac和iOS的应用程序,它使用.plist文件在使用iCloud的设备之间同步数据。每隔一段时间,我就会收到一封来自某个特定设备反复崩溃的人的电子邮件。(其他设备也可以)在任何情况下,应用程序都会在试图从iCloud读取文件时崩溃,使用NSPropertyListSerialization将数据转换为字典。在任何情况下,问题都可以通过让用户删除应用程序的iCloud数据来解决。同样的文件会重新同步,一切都会恢复正常 我将在这里使用的具体示例来自Mac版本,但我在iOS上遇到过几乎

我有一个适用于Mac和iOS的应用程序,它使用.plist文件在使用iCloud的设备之间同步数据。每隔一段时间,我就会收到一封来自某个特定设备反复崩溃的人的电子邮件。(其他设备也可以)在任何情况下,应用程序都会在试图从iCloud读取文件时崩溃,使用NSPropertyListSerialization将数据转换为字典。在任何情况下,问题都可以通过让用户删除应用程序的iCloud数据来解决。同样的文件会重新同步,一切都会恢复正常

我将在这里使用的具体示例来自Mac版本,但我在iOS上遇到过几乎相同的崩溃。从坠机报告中:

Exception Type:  EXC_BAD_ACCESS (SIGBUS)
Exception Codes: 0x000000000000000a, 0x0000000101ee2000

VM Regions Near 0x101ee2000:
    VM_ALLOCATE            0000000101ee1000-0000000101ee2000 [    4K] rw-/rwx SM=PRV  
--> mapped file            0000000101ee2000-0000000101ee3000 [    4K] r--/rwx SM=COW  /Users/USER/Library/Mobile Documents/PB4R74AA4J~com~junecloud~Notefile/*/*.notefile
    shared memory          0000000101ee3000-0000000101ee4000 [    4K] rw-/rw- SM=SHM  
然后:

Thread 7 Crashed:
0   libsystem_c.dylib               0x0000000105157013 bcmp + 19
1   com.apple.CoreFoundation        0x0000000101bbf4b0 __CFBinaryPlistGetTopLevelInfo + 80
2   com.apple.CoreFoundation        0x0000000101bbf36d __CFTryParseBinaryPlist + 93
3   com.apple.CoreFoundation        0x0000000101bbede2 _CFPropertyListCreateWithData + 146
4   com.apple.CoreFoundation        0x0000000101bcbdb0 CFPropertyListCreateWithData + 112
5   com.apple.Foundation            0x0000000101568b89 +[NSPropertyListSerialization propertyListWithData:options:format:error:] + 94
6   com.junecloud.Notefile-Helper   0x000000010107ad06 -[JUNNoteDocument readFromData:ofType:error:] + 64
7   com.apple.AppKit                0x000000010268d507 -[NSDocument readFromURL:ofType:error:] + 546
8   com.apple.AppKit                0x000000010228e3c8 -[NSDocument _initWithContentsOfURL:ofType:error:] + 135
9   com.apple.AppKit                0x000000010228e074 -[NSDocument initWithContentsOfURL:ofType:error:] + 262
10  com.junecloud.Notefile-Helper   0x000000010107cad8 -[JUNSyncDocument initWithFileURL:] + 213
11  com.junecloud.Notefile-Helper   0x0000000101079ec7 -[NotefileAppDelegate documentForURL:] + 68
12  com.junecloud.Notefile-Helper   0x00000001010825cb -[JUNSyncManager documentForURL:] + 76
13  com.junecloud.Notefile-Helper   0x000000010107d43c -[JUNSyncInOperation main] + 1340
14  com.apple.Foundation            0x0000000101563cd2 __NSThread__main__ + 1345
15  libsystem_c.dylib               0x00000001051697a2 _pthread_start + 327
16  libsystem_c.dylib               0x00000001051561e1 thread_start + 13

Thread 7 crashed with X86 Thread State (64-bit):
  rax: 0x0000000000000062  rbx: 0x000000000000007b  rcx: 0x000000010c2be868  rdx: 0x0000000000000007
  rdi: 0x0000000101d1e151  rsi: 0x0000000101ee2000  rbp: 0x000000010c2be810  rsp: 0x000000010c2be7b8
   r8: 0x000000010c2be870   r9: 0x0000000000000000  r10: 0x00007ff841c28900  r11: 0x00007ff841c186d8
  r12: 0x000000010c2be870  r13: 0x0000000101ee2000  r14: 0x000000010c2beb00  r15: 0x000000010c2be980
  rip: 0x0000000105157013  rfl: 0x0000000000010202  cr2: 0x0000000101ee2000
Logical CPU: 2
下面是它崩溃的相关代码:

- (BOOL)readFromData:(NSData *)data ofType:(NSString *)typeName error:(NSError **)outError {
    BOOL success = NO;
    NSDictionary *dictionary = nil;

    NSError *error = nil;
    id plist = [NSPropertyListSerialization propertyListWithData:data
        options:NSPropertyListImmutable format:NULL error:&error];
    if (plist && [plist isKindOfClass:[NSDictionary class]]) {
        dictionary = plist;
    } else {
        NSLog(@"Error opening document: %@ %@",error,[error userInfo]);
        if (outError != NULL) *outError = error;
    }

    // Then it does some things with the dictionary if it's not nil

    return success;
}
我是否正确地认为NSPropertyListSerialization只是阻塞了一些损坏的数据,或者问题更可能出现在我自己的代码中?如果问题在于NSPropertyListSerialization,我能做些什么来防止应用程序崩溃,并更恰当地处理问题

如果问题可能出现在我自己的代码中,我可以做些什么来查找原因?如果我可以自己复制这个问题,这会容易得多,但我从未在自己的设备上看到过这种崩溃,显然我不能指望用户给我访问他们的iCloud帐户的权限

按要求更新,这里有一点
junsynchDocument
。在iOS上这是UIDocument子类,在Mac上是NSDocument子类

- (id)initWithFileURL:(NSURL *)url {
    #if TARGET_OS_IPHONE

    self = [super initWithFileURL:url];
    return self;

    #else

    NSError *error = nil;
    if ([[NSFileManager defaultManager] fileExistsAtPath:[url path]]) {
        if ((self = [super initWithContentsOfURL:url ofType:[self documentType] error:&error])) {
            self.fileURL = url;
            self.hasUndoManager = NO;
        } else NSLog(@"Error initializing existing document: %@ %@",url,error); 
    } else {
        if ((self = [super initWithType:[self documentType] error:&error])) {
            self.fileURL = url;
            self.hasUndoManager = NO;
        } else NSLog(@"Error initializing new document: %@",error);
    }
    return self;

    #endif
}
这看起来很混乱,如果我在这里做傻事,我也不会感到惊讶。不过,它在大多数情况下都能正常工作。从
NotefileAppDelegate
调用的:

- (JUNSyncDocument *)documentForURL:(NSURL *)url {
    JUNNoteDocument *document = [[JUNNoteDocument alloc] initWithFileURL:url];
    return document;
}
而JUNSyncManager会依次调用它:

- (JUNSyncDocument *)documentForURL:(NSURL *)url {
    return [self.delegate documentForURL:url];
}
JUNSyncInOperation
调用:

JUNSyncDocument *document = [self.delegate documentForURL:self.url];
我刚刚意识到我可以通过使用
NSClassFromString
摆脱这个荒谬的委托链,但我不知道这是否会影响问题。

看看开源的


看起来崩溃的memcmp(bcmp)在一开始就检查了二进制plist头的前几个字节的数据。如果
CFDataGetLength
我也有同样的问题,(
UIDocument
&
NSDocument
子类,访问plist数据时崩溃),尽管我使用的是
NSFileWrapper

映射的文件路径在您的报告中看起来可疑(除非操作系统将其匿名化),它看起来不是实际的文件,而是查询字符串。是不是
NSMetadataQuery
返回了不正确的结果

到目前为止,我还没有解决办法,还在寻找

更新 我可以与客户一起调试这个问题,生成带有日志信息的自定义版本。以下是我的观察结果:

  • 崩溃发生在不同的API上,如
    NSPropertyListSerialization
    cImageSourceCreateWithURL
    ,以及其他许多API
  • 访问的文件存储在iCloud容器中
它具有以下状态:

fileExists = YES;
isUbiquitous = YES;
hasNonZeroSize = YES;
isDownloaded = NO;
因此,对于大多数API来说,它似乎是一个常规文件,但它不可用。当被访问时,它会使应用程序崩溃。 -被访问的文件可以位于具有
isdownload=YES
的文件包内,尽管被访问的文件本身(在文件包内)具有
isdownload=NO

解决方法:在访问文件内容之前,请检查文件的
isdownload
属性。使用以下方法检查此属性:

-[NSURL getResourceValue:&val forKey:NSURLUbiquitousItemIsDownloadedKey error:&error]
如果您像我一样使用
NSFileWrapper
阅读
UIDocument
内容,那么您需要签入以下内容:

-[UIDocument readFromURL:(NSURL *)url error:(NSError *__autoreleasing *)outError]
因为
NSFileWrapper
不会让您访问所需的文件包
NSURL


我怀疑创建文档时iCloud的原子性有问题。看起来文件包及其内容在下载状态下不同步,就像先创建文档目录,然后将其内容作为两个不同的操作复制到其中一样。

感谢提供所有详细信息。我一直在对我的应用程序进行更新,添加一个NSURLUbiquitousItemIsDownloadedKey检查。在我自己的测试中,似乎没有必要尝试读取已下载的文件,但似乎会自动触发下载。但可能情况并非总是如此,比如下载失败。所以,我怀疑这是我问题的正确答案,但我会等到我得到一些确认。