Могу ли я передать ссылку NSWindow на пользовательский объект и использовать этот объект для добавления NSButton и Action?

Мне было интересно, можно ли передать ссылку NSWindow на пользовательский объект, а затем использовать этот объект для добавления NSButton и связанного с ним действия/селектора для этой кнопки.

Кажется, у меня возникают проблемы, когда я пытаюсь это сделать. Когда я запускаю пример программы и нажимаю кнопку, возникает следующая ошибка времени выполнения: Поток 1: EXC_BAD_ACCESS (код = 1, адрес = 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

person GoatWarrior    schedule 22.07.2014    source источник


Ответы (1)


Во-первых, я предполагаю, что вы используете автоматический подсчет ссылок.

Когда вы нажимаете кнопку, приложение пытается вызвать метод pressCustomButton: цели кнопки, который экземпляр CustomObject устанавливает как себя. Однако этот экземпляр CustomObject уже освобожден.

Возьмите следующий код:

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    CustomObject *test = [[CustomObject alloc]init];
    [test createButton:_window];
}

После завершения вызова этого метода, если вы используете ARC, созданный вами экземпляр CustomObject будет освобожден. Поскольку подклассы NSControl, такие как NSButton, не сохраняют свои цели (чтобы избежать сохранения циклов/циклов сильной ссылки), это также приведет к освобождению экземпляра CustomObject. Это приведет к тому, что любые последующие сообщения этому экземпляру приведут к неожиданным результатам, например к сбою.

Чтобы предотвратить это, вам нужно оставить экземпляр CustomObject за пределами метода applicationDidFinishLaunching:. Есть несколько способов сделать это, например, сделать его свойством 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
person NSGod    schedule 22.07.2014