2

我已经编写了这个与文本字段相关联的简单操作方法。
每次我在文本字段中输入文本时,都会执行 PDF 中的搜索并PDFView自动滚动到选择:

- (IBAction) search:(id)id
{
    NSString *query = [self.searchView stringValue]; // get from textfield
    selection = [document findString: query fromSelection:NULL withOptions:NSCaseInsensitiveSearch]; 
    if (selection != nil)
    {
        [self.pdfView setCurrentSelection:selection];
        [self.pdfView scrollSelectionToVisible:self.searchView];
    } 
}

问题是经过 3 或 4 次搜索后,我进入EXC_BAD_ACCESS第 (i) 行。
如果我调试,我会看到该查询包含一个NSCFString而不是一个NSString.
我认为这是一个内存管理问题..但是在哪里?

在此处输入图像描述

我在一个简单的测试用例中复制了同样的问题:

  @interface PDFRef_protoTests : SenTestCase {
   @private

      PDFDocument *document;

   }

  ........

 - (void)setUp
  {
     [super setUp];
     document = [[PDFDocument alloc] initWithURL: @"a local url ..."];
  }

- (void)test_exc_bad_access_in_pdfdocument
{
    for (int i =0 ;i<100; i++)
    {
        NSString *temp;
        if (i % 2 == 0) temp = @"home";
        else if (i % 3 ==0) temp = @"cocoa";
        else temp=@"apple";
        PDFSelection *selection = [document findString: temp 
                                   fromSelection:nil 
                                withOptions:NSCaseInsensitiveSearch]; 
        NSLog(@"Find=%@, iteration=%d", selection, i);
    }
}

更新

1)如果我每次执行第二次搜索时都使用异步搜索(方法beginFindString:withOptions),似乎也会发生这种情况。

2) 我在 MacRuby 问题跟踪中发现了一个与我类似的问题:http: //www.macruby.org/trac/ticket/1029

3)似乎如果我暂时禁用垃圾收集,它会起作用,但内存会增加。我写了类似的东西:

[[NSGarbageCollector defaultCollector] disable];
[[NSGarbageCollector defaultCollector] enable];

周边搜索代码

另一个更新

非常奇怪的是,有时一切正常。比我清理和重建,问题再次出现。从某种角度来看,并不是 100% 可重现的。我怀疑 PDFKit 中的错误或我必须做的一些编译器设置

再次更新

亲爱的,这似乎很疯狂。我会专注于测试用例,它非常简单并且很容易复制问题。它出什么问题了?此测试用例仅在我禁用(通过代码或通过项目设置)GC 时才有效

另一个更新

男孩,这似乎是一个错误,但我从 Apple 网站下载了一个名为 PDFLinker 的示例(http://developer.apple.com/library/mac/#samplecode/PDFKitLinker2/Introduction/Intro.html#//apple_ref/doc/uid/DTS10003594)。这个例子实现了一个 PDFViewer。我的应用程序的代码和这个例子非常相似。对于同一个 PDF 的相同搜索操作,我的内存增加到 300/400 MB,而 PDFLinker 增加到 190MB。显然我的代码有问题。但我正在一点一点地比较它,我认为我没有插入内存泄漏(而且 Instrument 没有给我任何证据)。也许有一些项目范围的设置?

更新但从 64 位更改为 32 位内存消耗降低。64位和PDFKit肯定有问题。BTW 在第二次搜索时仍然是 EXC_BAD_ACCESS

解决方案 关键点是带有垃圾收集的 PDFKit 被窃听。如果我禁用 GC 一切正常。我遇到了另一个使我的分析变得复杂的问题:我在项目设置上禁用了 GC,但在目标设置上仍然启用了 GC。因此,Apple 的示例 PDFLinked2 有效,而我的无效。

4

5 回答 5

2

我同意您在 PDFKit 中发现了一个错误。

我在运行您的测试用例时遇到了各种形式的错误(分段错误、选择器不理解等)。将代码包装在@try/@catch中并不能防止与此方法相关的所有错误。

我在打印日志消息时也遇到了错误。

为了解决这些错误,我建议您在调用 -findString:fromSelection: 期间禁用 GC,正如您已经发现的那样。

此外,请务必在重新启用 GC 之前从选择中复制感兴趣的值。也不要只是复制选择

如果您从代码中的多个位置进行搜索,我还建议您提取一个单独的方法来执行搜索。然后你可以调用那个来为你进行搜索,而无需重复 GC 禁用/启用嵌套。

于 2011-06-17T05:46:16.807 回答
2

这类事情通常证明您正挂在指向已被破坏的对象的指针上。打开僵尸对象(带有NSZombieEnabled)以查看您访问坏对象的确切位置和时间。

于 2011-06-11T14:34:41.297 回答
1

保留PDFSelection *selection为成员变量并将其传入fromSelection:而不是nil.

可以PDFDocument保留返回的PDFSelection实例以提高性能。

于 2011-06-15T10:20:10.487 回答
1

您是否尝试在使用它之前保留 searchview 字符串值对象?

正如您所说,当您快速键入并且异步调用时会发生这种情况,对象指向的对象可能在您的对象指向它的时间和您在搜索中使用它的时间stringValue之间被释放。query

您可以尝试这样的事情来查看问题是否仍然存在:

- (IBAction) search:(id)id
{
    NSString *query = [[self.searchView stringValue] retain]; // get from textfield
    selection = [document findString: query fromSelection:NULL withOptions:NSCaseInsensitiveSearch]; 
    if (selection != nil)
    {
        [self.pdfView setCurrentSelection:selection];
        [self.pdfView scrollSelectionToVisible:self.searchView];
    } 

    [query release];

}

当然也有document被释放的可能性。你如何声明它?它是保留的属性吗?可以在您搜索的时候发布吗?

编辑:

我看到您发布了第二个参数为 的代码NULL,但在您的屏幕截图中,此值为nil.

文档说NULL当你想从头开始搜索时应该使用。

http://developer.apple.com/library/mac/#documentation/GraphicsImaging/Reference/QuartzFramework/Classes/PDFDocument_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40003873-RH2-DontLinkElementID_1

而且随着编译器的解释不同,这nil可能导致内部一些奇怪的行为。NULL

于 2011-06-15T00:46:43.407 回答
1

从您的屏幕截图来看,您似乎没有NSZombie打开电源。可能是它对您没有帮助的原因。开启它的方法如下:

如何在 Xcode 中启用 NSZombie?

您提供的屏幕截图在其他方面非常有用,但您确实需要NSZombie找出这种错误。好吧,除非很明显,否则它不是来自您发布的代码。


编辑:我阅读了您正在使用垃圾收集的评论。我是一名 iOS 开发人员,所以我在 Objective-C 中的垃圾收集经验非常有限,但据我所知NSZombie,在垃圾收集环境中不起作用。

我不确定是否可以在垃圾收集环境中获取 EXC_BAD_ACCESS,除非您创建自己的指针并尝试在没有创建对象的情况下对其调用方法,我不明白您为什么要这样做。

我听说有些框架不能很好地处理垃圾收集,但我认为 PDFKit 不在其中。无论如何,解决方案可能是不使用垃圾收集。也许您应该向 Apple 提交错误报告。

于 2011-06-11T22:13:11.523 回答