代码之家  ›  专栏  ›  技术社区  ›  Community wiki

琐碎PDFKit程序中怪异的EXC_BAD_ACCESS

  •  2
  • Community wiki  · 技术社区  · 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
    我认为这是内存管理问题。。但是在哪里?

    enter image description here

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

      @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 Issue Tracking中发现了一个与我类似的问题: http://www.macruby.org/trac/ticket/1029

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

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

    周围搜索代码

    另一个更新

    非常奇怪的是,有时一切都有效。然后我清理和重建,问题再次出现。从某种角度来看,它不是100%可复制的。我怀疑PDFKit或某些编译器设置中有错误

    再次更新

    亲爱的,这看起来很疯狂。我会把注意力集中在测试用例上,它非常琐碎,而且很容易复制问题。它怎么了?只有当我禁用(通过代码或项目设置)GC时,此测试用例才有效

    另一个更新

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

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

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

    5 回复  |  直到 14 年前
        1
  •  2
  •   Huperniketes    14 年前

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

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

    我在打印日志消息时也出现了错误。

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

    此外,一定要 制作副本 中感兴趣的值 选择 在重新启用GC之前。不要只是复制 选择 任何一个

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

        2
  •  2
  •   Jonathan Grynspan    14 年前

    这类事情通常是你挂在一个指向被破坏对象的指针上的证据。启用僵尸对象(使用 NSZombieEnabled )查看访问坏对象的确切位置和时间。

        3
  •  1
  •   Community Mohan Dere    8 年前

    从你的屏幕截图来看,你似乎没有 NSZombie 这可能是它对你没有帮助的原因。以下是打开它的方法:

    How to enable NSZombie in Xcode?

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


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

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

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

        4
  •  1
  •   cocoafan    14 年前

    保持 PDFSelection *selection 作为成员变量并传入 fromSelection: 而不是 nil

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

        5
  •  1
  •   Felipe Sabino    14 年前

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

    正如您所说,当您键入fast时就会发生这种情况,而异步调用也会发生这种情况 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

    正如编译器解释的那样 NULL 不同的是 能够 导致内部出现一些奇怪的行为。