2011-08-10 4 views
0

최근에 iPhone 앱을 개발하기 시작했습니다. C#에서 오는 Objective-C에는 나를위한 트랩이 있습니다. 다음 스 니펫에서 어떤 일이 일어 났는지 이해하지 못합니다.속성에 대한 액세스 개념 이해 문제

@interface RootViewController : UITableViewController { 
    NSString *simpleProperty; 
    NSString *propertyWithUnderscoreIvar; 
} 

@property (nonatomic, retain) NSString *simpleProperty; 
@property (nonatomic, retain) NSString *propertyWithUnderscoreIvar; 

@end 

@implementation RootViewController 

@synthesize simpleProperty; 
@synthesize propertyWithUnderscoreIvar = _propertyWithUnderscoreIvar; 

- (NSString *)simpleProperty { 
    return @"Simple property value"; 
} 
- (NSString *)propertyWithUnderscoreIvar { 
    return @"Property with underscore value"; 
} 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    NSLog([NSString stringWithFormat:@"%i %@", 1, simpleProperty]); 
    // --> 1 (null) 

    NSLog([NSString stringWithFormat:@"%i %@", 2, propertyWithUnderscoreIvar]); 
    // --> 2 (null) 

    NSLog([NSString stringWithFormat:@"%i %@", 3, _propertyWithUnderscoreIvar]); 
    // --> 3 (null) 

    NSLog([NSString stringWithFormat:@"%i %@", 4, self.simpleProperty]); 
    // --> 4 Simple property value 

    NSLog([NSString stringWithFormat:@"%i %@", 5, self.propertyWithUnderscoreIvar]); 
    // --> 5 Property with underscore value 
} 

왜 처음 세 출력이 null입니까? 속성에 대한 내 자신의 구현이 올바르지 않습니까?

답변

1

viewDidLoad 메서드에서 속성이 아닌 인스턴스 변수 (ivars)의 값을 기록합니다. 위의 코드 예제에서 : - simplePropertypropertyWithUnderscoreIvar

@interface RootViewController : UITableViewController { 
    NSString *simpleProperty; 
    NSString *propertyWithUnderscoreIvar; 
} 

이 클래스에서 두 개의 변수를 선언합니다. 반면에 다음 코드는 속성을 선언합니다.

@property (nonatomic, retain) NSString *simpleProperty; 
@property (nonatomic, retain) NSString *propertyWithUnderscoreIvar; 

다음은 선언입니다. 목표 C는 클래스 속성에 대한 getter 및 setter를 생성하는 쉬운 방법을 제공한다는 점에서 C#과 다소 유사합니다. Objective-C에서 이것은 키워드 (C# 자동 속성과 대략 유사 함)를 통해 이루어집니다. 구현 파일에

@synthesize simpleProperty; 
@synthesize propertyWithUnderscoreIvar = _propertyWithUnderscoreIvar; 

그 @synthesize 키워드는 속성을 위해, 당신을 위해 getter와 setter 메소드를 작성합니다. 첫 번째 합성은 좋아 보인다. 동일한 이름의 인스턴스 변수에 의해 뒷받침되는 'simpleProperty'에 대한 getter 및 setter를 생성한다. 두 번째 @synthesize는 hokey입니다. 그것은 선언하지 않은 인스턴스 변수 '_propertyWithUnderscoreIvar'에 의해 지원되는 'propertyWithUnderscoreIvar'에 대한 getter와 setter를 생성합니다. 이 코드는 현대 런타임에서는 작동하지만 레거시 런타임에서는 작동하지 않습니다 (현대 런타임에서도 @synthesize에 의해 'propertyWithUnderscoreIvar'ivar가 무시됩니다).

지금 당신의 코드가 로깅 코드, 널 (null)을 인쇄하는 이유에 당신은이 작업을 수행 :이 직접 인스턴스 변수에 액세스

NSLog([NSString stringWithFormat:@"%i %@", 1, simpleProperty]); 

. 그러나이 시점에서 인스턴스 변수를 어떤 값으로 설정하지 않았습니다. 당신이 정말로 의미하는 것은 지금처럼 속성에 액세스 할 수 있습니다 :

NSLog([NSString stringWithFormat:@"%i %@", 1, [self simpleProperty]); 

당신이해야 할 노력하고 무엇 하드 코딩 값을 방법 simpleProperty를 호출하고 반환하는 대신 [self simpleProperty] 사용.

+0

@Sandro - 귀하가 그 의견을 말하면서 편집하고있었습니다. 당신이 ivars를 선언하는 위치에 대한 확장 된 답변을 참조하십시오. – Perception

+0

감사합니다. 나는 스 니펫을 약간 썼다. 이제 인스턴스 변수에 밑줄 접두사를 사용하지 않습니까? – Sandro

+0

ivar과 속성을 구별하는 데 도움이되는 코드 작성 방법으로 (실제로 속성을 사용하려고했을 때 실수로 ivar을 사용하는 것과) 동일한 문제를 피할 수 있습니다. – Perception

0

- (NSString *)simpleProperty { 
    return @"Simple property value"; 
} 
- (NSString *)propertyWithUnderscoreIvar { 
    return @"Property with underscore value"; 
} 

는 접근이다. In

NSLog([NSString stringWithFormat:@"%i %@", 1, simpleProperty]); 

당신은 직접 ivar에 액세스하고 있습니다. 따라서이 ivars는 당신이 아무것도 설정하지 않았기 때문에 null입니다. In

NSLog([NSString stringWithFormat:@"%i %@", 4, self.simpleProperty]); 

당신은 접근자를 통해 ivar에 액세스하고 있습니다. 따라서 런타임은 접근자를 호출합니다. 제 생각에는 @synthesize을 사용할 때 자신의 접근자를 작성하면 안됩니다. 적어도 Objective C를 작성하기 시작했을 때 접근 자 또한 이상합니다.

+0

하지만 인스턴스 변수는 선언하지 않습니다. '@synthesize propertyWithUnderscoreIvar = _propertyWithUnderscoreIvar; – Sandro

+0

@synthesize는 속성에 대한 인스턴스 변수를 생성합니다. 어딘가에 보관해야합니다. –

0

getter/setter 메서드에 액세스하려면 self 또는 instance을 사용해야합니다.

NSLog([NSString stringWithFormat:@"%i %@", 1, self.simpleProperty]); 

위의 행은 예상대로 @"Simple property value"을 인쇄합니다.

+0

FWIW, 아무도 그가 NSLog (@ "% i : % @", 1, self.simpleProperty);를 직접 호출 할 수 있다고 언급하는 것 같습니다. NSLog()는 이미 내부적으로 (예를 들어) 비슷한 일을하기 때문에'[NSString stringWithFormat : ...]'을 사용할 필요가 없습니다. –