1

在我的应用程序中有一个NSWindowController. 在- (void)awakeFromNib我创建一个NSView子类的实例以创建底部放置的按钮栏:

self.buttonBar = [[CNButtonBar alloc] initWithSize:NSMakeSize(tableViewRect.size.width-1, 25)];

这个CNButtonBar东西有一个方法可以给自己添加按钮。我创建了两个:

[buttonBar addButtonWithTitle:nil
                        image:[NSImage imageNamed:NSImageNameAddTemplate]
                       target:self
                       action:@selector(btnAccountAddAction:)
                    alignment:CNBarButtonAlignLeft];

[buttonBar addButtonWithTitle:nil
                        image:[NSImage imageNamed:NSImageNameRemoveTemplate]
                       target:self
                       action:@selector(btnAccountRemoveAction:)
                    alignment:CNBarButtonAlignLeft];

NSViewController这两个操作方法是在我发送这两个addButtonWithTitle:...消息的同一实例中定义的。

用于设置动作的方法定义如下:

- (void)btnAccountAddAction:(id)sender
{
    ....
}

- (void)btnAccountRemoveAction:(id)sender
{
    ....
}

但是,它不起作用。每次如果我单击这两个按钮之一,我的应用程序就会崩溃并抛出如下异常:

-[__NSArrayM btnAccountAddAction:]: unrecognized selector sent to instance 0x1001454e0

检查过这个异常是绝对正确的。NSArray没有我想调用的这种方法。但是,有时抛出此异常的对象会发生变化。有时有一个__NSData对象,有时有一个__NSDictionary等等。似乎接收器不是我的NSWindowController子类。但是给定的实例 ID0x1001454e0与我的相同NSWindowController

它让我想把头发扯下来!这里出了什么问题……?谢谢。


更新

我不得不说,CNButtonBarCNButtonBarButton都是完全由代码绘制的。的完整方法在addButtonWithTitle:image:target:action:alignment:这里(请记住,这发生在CNButtonBar的子类中NSView(我应该使用NSViewController它来代替它吗?),CNButtonBarButton是 的子类NSButton):

- (void)addButtonWithTitle:(NSString*)title image:(NSImage*)image target:(id)target action:(SEL)action alignment:(CNBarButtonAlign)align
{
    if (self.buttons == nil)
        self.buttons = [[NSMutableArray alloc] init];

    CNButtonBarButton *button = [[CNButtonBarButton alloc] init];
    [self.buttons addObject:button];

    button.title = title;
    button.image = image;
    button.target = target;
    button.action = action;
    button.align = align;

    NSRect buttonRect;
    NSSize titleSize = NSMakeSize(0, 0);
    if (button.title.length > 0) {
        NSMutableParagraphStyle* textStyle = [[NSMutableParagraphStyle defaultParagraphStyle] mutableCopy];
        [textStyle setAlignment: NSCenterTextAlignment];

        NSColor *textColor = [[NSColor blackColor] colorWithAlphaComponent:0.9];
        NSShadow* textShadow = [[NSShadow alloc] init];
        [textShadow setShadowColor: [NSColor whiteColor]];
        [textShadow setShadowOffset: NSMakeSize(0, -1)];
        [textShadow setShadowBlurRadius: 0];

        button.titleTextAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
                                      [NSFont fontWithName:@"Helvetica Neue" size:11.0], NSFontAttributeName,
                                      textShadow,                     NSShadowAttributeName,
                                      textColor,                      NSForegroundColorAttributeName,
                                      textStyle,                      NSParagraphStyleAttributeName,
                                      nil];
        titleSize = [title sizeWithAttributes:button.titleTextAttributes];
        buttonRect = NSMakeRect(0, 0, roundf(titleSize.width) + kTextInset * 2, NSHeight(self.frame) - 1);

    }

    if (button.image != nil) {
        NSSize imageSize = [image size];
        if (button.title.length == 0) {
            buttonRect = NSMakeRect(0, 0, imageSize.width + kImageInset * 2, NSHeight(self.frame) - 1);

        } else {
            buttonRect = NSMakeRect(0, 0,
                                    (imageSize.width + kImageInset * 2) + (roundf(titleSize.width) + kTextInset),
                                    NSHeight(self.frame) - 1);
        }
    }

    switch (self.align) {
        case CNButtonBarAlignNormal: {
            switch (button.align) {
                case CNButtonBarButtonAlignLeft: {
                    button.frame = NSMakeRect(offsetLeft, 0, NSWidth(buttonRect), NSHeight(buttonRect));
                    offsetLeft += 1 * [self.buttons indexOfObject:button] + NSWidth(button.frame);
                    break;
                }

                case CNButtonBarButtonAlignRight: {
                    button.frame = NSMakeRect(offsetRight - NSWidth(buttonRect), 0, NSWidth(buttonRect), NSHeight(buttonRect));
                    offsetRight -= 1 * [self.buttons indexOfObject:button] + NSWidth(button.frame);
                    break;
                }
            }
            break;
        }

        case CNButtonBarAlignCentered: {
            break;
        }
    }
    [self addSubview:button];
}

更新 2

问题已经解决了。经过一些调试,我发现这一定是 ARC 自动保留/释放的问题。我是对的。但问题是我的NSViewController子类。由于将实例作为局部变量(没有强指针)而泄漏。感谢Sean D.,这为我指明了正确的方向。(-;

4

1 回答 1

2

Looks like one of two things is happening. The first possibility is that your CNButtonBar object is getting released while the buttons are still around. If the buttons are still there, they'll try to send those selectors to whatever happens to occupy the memory the CNButtonBar used to be in. I'd say make sure it isn't autoreleasing itself anywhere, and that you're not accidentally autoreleasing it in the window controller's -awakeFromNib method. (If you're anything like me, that's the most likely culprit.)

The second possibility is that your -addButtonWithTitle:image:target:action:alignment: method is setting the buttons' actions but not their targets. Make sure your implementation of that method calls -setTarget: as well as -setAction: on the button.

于 2012-07-29T03:42:01.610 回答