본문 바로가기

Programming Language/Objective-C

이벤트 처리시 멤버에 들어간 배열 접근에서 EXC_BAD_ACCESS 오류가 뜰 경우

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

다음과 같이 버튼 하나 있고 내부적으로 배열을 가지고 있는 창이 하나 있다고 가정합니다. 버튼을 클릭하면 button_Click 메서드가 실행됩니다.

// TestDelegate.h
#import <Cocoa/Cocoa.h>

@interface TestDelegate : NSObject <NSApplicationDelegate>
{
	NSArray * array;
	NSWindow * window;
	NSButton * button;
}

@property (nonatimic, retain) NSArray * array;
@property (assign) IBOutlet NSWindow * window;
@property (nonatomic, retain) IBOutlet NSButton * button;

- (IBAction) button_Click: (NSButton *) sender;

@end
 // TestDelegate.m
#import "TestDelegate.h"

@implementation TestDelegate

@synthesize array;
@synthesize window;
@synthesize button;

- (void) applicationDidFinishLaunching: (NSNotification *) aNotification
{
	self.array = [NSArray arrayWithObjects: [NSNumber numberWithInteger: 0], nil];
}

- (IBAction) button_Click: (NSButton *) sender
{
	NSLog(@"배열의 첫째 원소는 %d", [[[self array] objectAtIndex: 0] integerValue]);
}
@end

겉 보기에는 별 문제가 없어 보입니다.
앱이 실행되면 array 포인터가 NSArray의 arrayWithObjeccts: 메서드에 의해 초기화된 배열을 가지고 있고,
버튼을 클릭해서 button_Click이 실행되면 이 배열의 0번째 원소에 접근해서 콘솔에 값을 출력하는 것이니까요. 하지만 실제로 실행해보면 EXC_BAD_ACCESS 오류가 발생합니다.
applicationDidFinishLaunching이 끝나고 button_Click이 실행되기 전까지 array가 사용되지 않았으므로 저절로 메모리가 해제되어 버린 것입니다.
이 때는 array가 갖는 포인터를 Mac OS가 저절로 해제하지 않도록 지정해야 합니다. 대신, 해제하는 시점에 제대로 해제되도록 프로그래머가 직접 지정해야 합니다.

아래와 같이 NSArray형 인스턴스에 retain 메시지를 보내서 그 반환값을 멤버변수에 저장하면 액세스 위반 오류가 뜨지 않고 잘 실행됩니다.

self.array = [[NSArray arrayWithObjects: [NSNumber numberWithInteger: 0], nil] retain];

대신 dealloc 메서드를 재정의해서 직접 해당 배열을 해제해줘야 합니다.

// TestDelegate.h
#import <Cocoa/Cocoa.h>

@interface TestDelegate : NSObject <NSApplicationDelegate>
{
	NSArray * array;
	NSWindow * window;
	NSButton * button;
}

@property (nonatimic, retain) NSArray * array;
@property (assign) IBOutlet NSWindow * window;
@property (nonatomic, retain) IBOutlet NSButton * button;

- (void) dealloc;
- (IBAction) button_Click: (NSButton *) sender;

@end
 // TestDelegate.m
#import "TestDelegate.h"

@implementation TestDelegate

@synthesize array;
@synthesize window;
@synthesize button;

- (void) applicationDidFinishLaunching: (NSNotification *) aNotification
{
	self.array = [NSArray arrayWithObjects: [NSNumber numberWithInteger: 0], nil];
}

- (void) dealloc
{
	[[self array] release];
	[super dealloc];
}

- (IBAction) button_Click: (NSButton *) sender
{
	NSLog(@"배열의 첫째 원소는 %d", [[[self array] objectAtIndex: 0] integerValue]);
}
@end


'Programming Language > Objective-C' 카테고리의 다른 글

Objective-C에서 SQLite 사용 예제  (0) 2018.07.27
NSDate로 현재 날짜 얻기  (0) 2012.04.28
NSString과 C 문자열간 변환하기  (0) 2012.02.26
Objective-C 첫 예제  (0) 2012.01.21