2011-12-20 2 views
6

나는 이미 게시 된 질문을 광범위하게 읽었으므로 찾고있는 대답을 찾을 수 없습니다.목표 C - 접근 자 즉 Getters/Setters

나는 완전히 (내가 @property int width@synthesize width이 있다면 즉, 내가 실수 width의 getter 메소드와 setWidth:의 setter 메소드를 만드는 오전) getter와 setter 메소드를 만들 @syntesize 지시어를 사용하여 개념을 이해합니다.

그러나 @synthesize 지시문을 사용하고 있지 않지만 객체 인 @implementation 섹션의 인스턴스 변수를 선언 할 때 접근 자 방법의 작동 방식을 완전히 이해하지 못했습니다.

1) main에 말한다 : 처음 그 [myRect origin1]를 결정하는 것 [[myRect origin1] x] 메소드를 호출하는 것처럼

NSLog(@"Origin at (%i, %i)", myRect.origin1.x, myRect.origin1.y); 

그것은 나에게 나타납니다 이것은 내가 다음 코드에 대해 이해하지 못하는 것입니다 origin을 반환하고 즉시 [origin x]을 호출합니다 (그리고 y에 대해서도 동일하게 수행합니다). 자, 저를 발생하는 것은 사실입니다 나는 프로그램이 오류의 톤을 얻고 중단

-(XYpoint *) origin2; 

-(XYpoint *) origin1; 

이 Rectangle.h에 포함 된 getter 메소드의 이름을 변경한다면 엮다. 참고 : 나는 또한 사방이 방법의 이름을 변경 그 것이다 나 또한에서 setter 메소드의 이름을 변경하는 경우에는

NSLog(@"Origin at (%i, %i)", myRect.origin2.x, myRect.origin2.y); 

에 주에 위의 코드 변경을 포함하여 참조 :에

-(void) setOrigin1: (XYpoint *) pt 

:

-(void) setOrigin2: (XYpoint *) pt 

모든 것이 이전처럼 작동합니다. 내 getter와 setter가 둘 다 xsetX 명명 규칙에 명명 된 경우에만 제대로 작동하는 것 같습니다. 나는 이것이 내가 주로 필요한 부분이라고 생각한다 :

가) 객체 (예 : 'origin')와 같은 인스턴스 변수를 만들면, getter와 setter 메소드를 생성해야합니까?

B는) 내가 그 getter 메소드 아니지만 setter 메소드 또는를 만들 수도 마찬가지

C)가 필수 그게 나는 그들이 모두에 이름이 될 수 있음을 '기원'에 대한 getter와 setter 방법 모두를 생성 할 경우 xsetX 방식. 이 경우 -(XYpoint *) origin1-(void) setOrigin1: (XYpoint *) pt입니다. getter의 이름을 변경하는 경우 그에 따라 setter의 이름을 변경해야합니다.

여기에 모든 코드입니다 :

Rectangle.h :

#import <Foundation/Foundation.h> 
@class XYpoint; 

@interface Rectangle : NSObject 

@property int width, height; 

-(XYpoint *) origin1; 
-(void) setOrigin1: (XYpoint *) pt; 
-(void) setWidth: (int) w andHeight: (int) h; 
-(int) area; 
-(int) perimeter; 

@end 

사각형.m :

#import "Rectangle.h" 

@implementation Rectangle 
{ 
    XYpoint *origin; 
} 

@synthesize width, height; 

-(void) setWidth:(int) w andHeight:(int)h 
{ 
    width = w; 
    height = h; 
} 


-(void) setOrigin1: (XYpoint *) pt 
{ 
    origin = pt; 
} 

-(int) area 
{ 
    return width * height; 
} 

-(int) perimeter 
{ 
    return (width + height) * 2; 
} 

-(XYpoint *) origin1 
{ 
    return origin; 
} 

@end 

XYpoint.h :

#import <Foundation/Foundation.h> 

@interface XYpoint : NSObject 

@property int x, y; 

-(void) setX: (int) xVal andY: (int) yVal; 
@end 

XYpoint.m :

#import "XYpoint.h" 

@implementation XYpoint 

@synthesize x,y; 

-(void) setX: (int) xVal andY: (int) yVal 
{ 
    x = xVal; 
    y = yVal; 
} 
@end 

main.m : 당신은 가능성이 가장 높은 방법을 변경하는 것을 잊었다

#import <Foundation/Foundation.h> 
#import "Rectangle.h" 
#import "XYpoint.h" 

int main (int argc, const char * argv[]) 
{ 

    @autoreleasepool { 
     Rectangle *myRect = [[Rectangle alloc] init]; 
     XYpoint *myPoint = [[XYpoint alloc] init]; 

     [myPoint setX: 100 andY: 200]; 
     [myRect setWidth: 5 andHeight:8]; 
     myRect.origin1 = myPoint; 
     NSLog(@"Rectangle w = %i, h = %i", myRect.width, myRect.height); 
     NSLog(@"Origin at (%i, %i)", myRect.origin1.x, myRect.origin1.y); 
     NSLog(@"Area = %i, Perimeter = %i", [myRect area], [myRect perimeter]); 
    } 
    return 0; 
} 
+0

도트 표기법은 접근 자 호출의 바로 단축형입니다. myRect.origin2는 [myRect origin2] 또는 [myRect setOrigin2]와 같을 수 있기 때문에 컨텍스트에 따라 도트 표기법을 사용하려면 두 액세서를 모두 정의해야합니다. 그럼에도 불구하고 Jakob의 대답처럼 실제로 인스턴스 변수를 속성으로 선언해야합니다. – spwert

+0

고마워요! 그게 내 문제 야. getter (또는 setter)를 setOrigin1에서 setOrigin2로 변경하면 myRect.origin1을 호출 할 때 그에 따라 getter/setter가 모두 필요합니다. 그리고 setOrigin1을 setOrigin2로 변경 했으므로 더 이상 getter와 setter가 둘 다 없습니다. 비록 내가 그것을 사용하지 않더라도 컴파일러는 그것을 요구한다. 적어도 나는 당신이 의미하는 바를 믿습니다. 그렇다면 이제는 나에게 의미가있다. 비록 내가 당신에게 "올바른"대답을주는 방법을 모르겠지만, 단지 코멘트로 나열된 이후 – ReiAndCoke

+0

이것은 잘못된 것입니다. 두 접근 자 모두 필요하지 않습니다. 헤더 파일에'- (int) foo;'를 정의하면'int x = myObj.foo;'를 사용할 수있다. 반면, 헤더 파일에'- (void) setBar : (int) anInt;'를 정의하면,'myObj.bar = 15;'를 사용할 수있다. 게터와 세터는 독립적입니다. –

답변

3

토론 후 전자 메일을 통해 문제가 실제로 clang의 버그 인 것으로 나타났습니다. 다음과 같은 미니 프로그램을 고려 :

#import <Foundation/Foundation.h> 

@interface TestObject : NSObject 
-(void)setIdVar:(id)someId; 
@end 

@implementation TestObject 
-(void)setIdVar:(id)someId; 
{ 
    NSLog(@"-setIdVar called with argument: %@", someId); 
} 
@end 

int main (int argc, const char * argv[]) 
{ 
    @autoreleasepool { 
     TestObject *testObj = [[TestObject alloc] init]; 
     testObj.idVar = @"test"; 
    } 
    return 0; 
} 

은 분명히, 우리는이 프로그램을 실행하고 출력 -setIdVar called with argument: test 기대합니다. ARC없이 컴파일하면 정확히 어떻게되는지 알 수 있습니다 (예 : clang -framework Foundation main.m 사용).

하지만 ARC로 컴파일하면 clang이 작동하지 않습니다. (clang -framework Foundation -fobjc-arc main.m)

재미있는 점은 비 객체 유형 (예 : int) 또는 getter가 정의 될 때 setter를 사용할 때이 충돌이 발생하지 않는다는 점입니다.

3

헤더 또는 구현 파일의 이름 읽기 전용 속성 (setter 메서드가 없음)을 갖는 것은 완벽합니다.

점 표기법 (예 : myRect.origin1)을 사용하여 액세스하려는 객체 속성이있는 경우 모범 사례는 헤더 파일에서 해당 속성을 정의해야합니다.

@property(readonly) XYPoint *origin1; // for read only properties 
@property(retain) XYPoint *origin1; // for read/write properties 

당신이 @synthesize를 사용하지 않는 경우에도 그들을 사용하고 헤더 파일에 일반 메소드 선언 대신 사용할 : 같은 라인을 포함한다. 이 라인은 실제로 getter와 setter를 생성하지 않으며, 클래스에 이러한 속성이 있음을 컴파일러에 알립니다. 그러면 컴파일러는 -origin1-setOrigin1이라는 getter (및 읽기 전용을 사용하지 않는 경우 setter)를 예상합니다. setter/getter의 이름이 중요합니다 (자세한 내용은 Apple의 키 - 값 코딩 관련 문서 참조)

또한 Cocoa의 메모리 관리 지침을 알고 있어야합니다. 자동 참조 카운팅을 사용하지 않는 한 Rectangle 클래스는 setter에서 XYPoint 객체를 유지하거나 복사합니다. [편집] : 방금 @autoreleasepool 구문을 사용하기 때문에 분명히 ARC를 사용하고 있다는 것을 알았습니다.

+0

헤더 파일과 구현 파일의 이름이 변경되었습니다. 여전히 getter 및 setter 메서드의 이름이 "origin1"및 "setOrigin1"이지만 "origin1"및 "setOrigin2"가 아닌 경우에는 많은 오류가 발생합니다. 그런 다음 "setOrigin2"를 "setOrigin1"로 다시 변경하면 다시 작동합니다. 조금 혼란 스럽다면 미안합니다. – ReiAndCoke

+0

이것은 정말로 당황 스럽습니다. setOrigin1 setter 메서드의 이름을 변경하면 (그리고 참조 된 다른 곳에서는 그 이름이 바뀌어도) 내 프로그램에서 모든 종류의 오류가 발생하는 이유는 무엇입니까? 나에게 그것이 origining1 getter 메소드와 함께 더 이상 지명되지 않기 때문에 그것은 오류를 얻는 것처럼 보인다. – ReiAndCoke

+0

정말 어딘가에 오타 같아요. 정확한 경고와 소스 파일을 보지 않으면 무엇이 잘못되었는지 분석하기가 어렵습니다. 도트 표기법을 사용하여 속성에 액세스 할 때의 문제는 컴파일러가 getters/setter의 이름이 무엇인지 절대적으로 확신해야한다는 것입니다. 가장 좋은 방법은'- (id) foo;'와'- (void) setFoo : (id) aFoo() 메소드를 선언하는 대신'@property id foo;'구문을 사용하여 헤더 파일에이 속성을 선언하는 것이다. ; 그리고 컴파일러가 이들이 속성이라고 생각하기를 바란다. –

5

A) 나는 그것을 위해 getter와 setter 메소드를 작성해야합니다 대상이 경우 (같은 '기원') 될 일이 인스턴스 변수를 작성하는 경우?

아니요. 속성을 선언하는 경우 고유 한 접근자를 제공하거나 @synthesize 지시문을 사용하여 속성을 만들어야합니다. 그러나 접근자를 갖지 않고도 원하는 모든 인스턴스 변수를 가질 수 있습니다.

B는) 내가 getter 메소드 아니지만 setter 메소드 또는 재산 readonly를 선언하는 경우 그 반대의 경우도 마찬가지

예, 방금 게터를 제공 할 수 있습니다를 만들 수 있습니다.

C)를 의무화 그게 내가 게터하고 모두가 X setX 방식이라는 것이 '기원'에 대한 세터 방법 모두를 생성 할 경우. 이 경우 - (XYpoint *) origin1 및 - (void) setOrigin1 : (XYpoint *) pt. getter의 이름을 변경하는 경우 그에 따라 세터의 이름을 변경해야합니다.

당신은 접근에 대한 자신의 이름을 제공 할 수 있지만, 당신은 당신의 클래스가 문제의 속성에 대한 준수 코딩 키 값이 될하려는 경우 일반적인 규칙을 고수해야

@property (getter=isBar, setter=setBar) int bar; 
관련 문제