我想知道是否有可能将NSWindow的引用传递给自定义对象,然后使用该对象为该按钮添加NSButton和相关的操作/选择器。
当我尝试这个时,我似乎遇到了问题。当我运行示例程序并单击按钮时,发生以下运行时错误:线程1:EXC_BAD_ACCESS (code=1, address=0x18)
下面是我的代码:// AppDelegate.h
#import <Cocoa/Cocoa.h>
@interface AppDelegate : NSObject <NSApplicationDelegate>
@property (assign) IBOutlet NSWindow *window;
@end
// AppDelegate.m
#import "AppDelegate.h"
#import "CustomObject.h"
@implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
CustomObject *test = [[CustomObject alloc]init];
[test createButton:_window];
}
@end
// CustomObject.h
#import <Foundation/Foundation.h>
@interface CustomObject : NSObject
{
int test;
NSButton *testButton;
}
- (IBAction)pressCustomButton:(id)sender;
-(void)createButton:(NSWindow*)win;
@end
// CustomObject.m
#import "CustomObject.h"
@implementation CustomObject
-(IBAction)pressCustomButton:(id)sender
{
NSLog(@"pressCustomButton");
}
-(void)createButton:(NSWindow*)win
{
testButton = [[NSButton alloc] initWithFrame:NSMakeRect(100, 100, 200, 50)];
[[win contentView] addSubview: testButton];
[testButton setTitle: @"Button title!"];
[testButton setButtonType:NSMomentaryLightButton]; //Set what type button You want
[testButton setBezelStyle:NSRoundedBezelStyle]; //Set what style You want
[testButton setTarget:self];
[testButton setAction:@selector(pressCustomButton:)];
}
@end
首先,我假设您正在使用自动引用计数。
当您单击按钮时,应用程序尝试调用按钮目标的pressCustomButton:
方法,CustomObject
的实例将其设置为自身。但是,CustomObject
的实例已经被释放了。
取以下代码:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
CustomObject *test = [[CustomObject alloc]init];
[test createButton:_window];
}
一旦该方法被调用完成,如果您正在使用ARC,您创建的CustomObject
实例将被释放。由于NSControl
的子类如NSButton
不保留它们的目标(为了避免保留周期/强引用周期),这也会导致CustomObject
实例被释放。这将导致该实例的任何后续消息产生意想不到的结果,例如崩溃。
为了防止这种情况,您需要在applicationDidFinishLaunching:
方法之外保留CustomObject
实例。有几种方法可以做到这一点,例如使其成为AppDelegate
的属性,或者如果您计划拥有多个对象,则使用NSMutableArray
来存储它们。
类似如下:
@interface AppDelegate : NSObject <NSApplicationDelegate>
....
@property (nonatomic, strong) NSMutableArray *customObjects;
@end
// AppDelegate.m
#import "AppDelegate.h"
#import "CustomObject.h"
@implementation AppDelegate
- (id)init {
if ((self = [super init])) {
customObjects = [[NSMutableArray alloc] init];
}
return self;
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
CustomObject *test = [[CustomObject alloc]init];
[customObjects addObject:test];
[test createButton:_window];
}
@end