【问题标题】:Where is this NSView being deallocated to cause bad access error?这个 NSView 在哪里被释放以导致错误的访问错误?
【发布时间】:2014-01-12 07:44:39
【问题描述】:

我正在编写一个应用程序,用户应该能够单击按钮并切换视图。我创建了IBActions,将我的方法 switchSubView 加载到所需的视图上,但这样做时遇到了一些问题。我目前已经编写了方法来动画两个NSViews 之间的过渡,这些NSViews 通过Interface Builder 作为IBOutlets 连接。我可以使用这些方法在两个视图之间转换,但是当我尝试从初始视图切换到另一个视图,然后切换到另一个视图,然后再切换回来时,我得到EXC_BAD_ACCESS。我似乎无法调试问题。调试器显示两个NSView 对象以指向不同的内存位置。为了澄清,我想在应用程序执行期间重用视图。我不希望任何视图被释放。

代码如下:

- (void)switchSubViews:(NSView *)firstView withView:(NSView *)secondView {
    [firstView setSubviews:[NSArray array]];
    [self prepareViews:firstView];
    [[firstView animator] addSubview:secondView];
}

/* Make a "move" animation effect. */
- (void)prepareViews:(NSView *)prepareView {
    CATransition * transition = [CATransition animation];
    [transition setType:kCATransitionPush];
    [transition setSubtype:kCATransitionFromRight];
    [prepareView setAnimations:[NSDictionary dictionaryWithObject:transition forKey:@"subviews"]];
    [prepareView setWantsLayer:YES];
}

基本上,我会这样称呼它,给定 initialView 和 newView:

[self switchSubViews:initialView withView:newView];

谁能帮我调试一下?

谢谢。

更新:在注释掉 for 循环和 removeFromSuperview 代码进行调试后,我仍然收到错误的访问错误。视图的属性设置为@property (nonatomic, strong),那么视图不应该保留吗?如果没有,我如何在启用 ARC 的情况下明确保留我的 NSView?是否可以告诉 ARC 保留它,或者它已经保留了视图,因为它是用 @property(nonatomic, strong) 设置的?

第二次更新:我研究了一下,发现我可以通过创建一个指向对象的强指针来使 ARC 保留该对象。我通过创建实例变量进行了尝试:

@interface AppDelegate : NSObject <NSApplicationDelegate, NSWindowDelegate> {
    /* Some instance variables here... */
    __strong NSView * retainFirstView;
    __strong NSView * retainSecondView;
}

@property (nonatomic, strong) NSView * retainFirstView;
@property (nonatomic, strong) NSView * retainSecondView;

然后在.m文件中:

#import <Quartz/Quartz.h> /* Animation. */
#import "AppDelegate.h"
/* Some other imports necessary... */

@implementation AppDelegate

@synthesize retainFirstView;
@synthesize retainSecondView; 

/* Some subview switching code... */
[self setRetainFirstView:firstView];
[self setRetainSecondView:secondView];

@end

但我仍然收到错误消息。似乎我正在换出的视图一直被解除分配。我在这方面花费了大量时间,但无法摆脱错误。任何帮助,将不胜感激。如果这不是保留视图的正确方法,请告诉我。

更新 3:为了测试,我暂时禁用了 ARC,并在调用 setSubviews 或 addSubview 之前执行了此操作:

[firstView retain]; 
[secondView retain];

它仍然失败。我很困惑,因为我不再看到可能导致释放的原因。

更新 4:我通过在 Xcode 中执行 Product -> Profile 检查了僵尸和发送到已释放对象的消息,令我惊讶的是,我没有收到任何通知。我很困惑为什么会发生这种情况。

【问题讨论】:

    标签: objective-c macos cocoa automatic-ref-counting nsview


    【解决方案1】:

    你得到EXC_BAD_ACCESS,因为如果没有其他东西保留它,调用-removeFromSuperview 将释放该视图。很可能正在释放的视图(因此有一个指向垃圾的对象指针)稍后会传递给-switchSubviews:withView,从而导致您的崩溃。在调用 -removeFromSuperview 之前,您应该始终保留稍后将要使用的视图,以确保它们不会被释放。

    作为旁注,-switchSubviews:withView: 的代码是不必要的复杂。可以简化为:

    - (void)switchSubViews:(NSView *)firstView withView:(NSView *)secondView {
        firstView.subviews = [NSArray array];
        [self prepareViews:firstView];
        [[firstView animator] addSubview:secondView];
    }
    

    【讨论】:

    • 谢谢你,我自己可能永远也想不通。但我还有一个小问题。如果我的项目使用 ARC,我如何保留视图?我不允许显式调用保留消息。
    • 似乎即使在注释掉removeFromSuperview代码进行调试后,错误仍然存​​在。这意味着视图正在被释放,但我无法从哪里找到。我使用属性(非原子,强)设置视图属性,这是否意味着视图应该由 ARC 保留?
    • 那么我应该保留firstView的每个子视图吗?如果是这样,我该怎么做?
    • 您应该保留您计划稍后使用的任何子视图。在 ARC 下,您不会显式发送 -retain-release 消息,但它仍然支持像 strongweak 这样的存储说明符来管理对象图中的引用。例如,您可以将子视图存储在一个数组中,并将它们分配给这样声明的属性:@property (strong) NSArray *viewArray
    • 非常感谢!我设法使用您对 NSArray * viewArray 的建议使其工作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多