코코아 objective-c 클래스에서 변수 앞의 밑줄은 어떻게 작동합니까?


157

몇 가지 iPhone 예제에서 속성이 변수 앞에 밑줄 _을 사용했다는 것을 보았습니다. 누구나 이것이 무엇을 의미하는지 알고 있습니까? 아니면 어떻게 작동합니까?

내가 사용하는 인터페이스 파일은 다음과 같습니다.

@interface MissionCell : UITableViewCell {
    Mission *_mission;
    UILabel *_missionName;
}

@property (nonatomic, retain) UILabel *missionName;

- (Mission *)mission;

위의 내용이 정확히 확실하지 않지만 임무 이름을 다음과 같이 설정하려고 할 때

aMission.missionName = missionName;

오류가 발생합니다.

구조 또는 공용체가 아닌 멤버 'missionName'에 대한 요청

답변:


97

ivar에 밑줄 접두어를 사용하는 경우 (일반적인 규칙에 불과하지만 유용한 규칙), 자동 생성 된 접근자가 (속성에 대해) 사용할 ivar을 알 수 있도록 한 가지 추가 작업을 수행해야합니다. 구체적으로 구현 파일에서 synthesize다음과 같아야합니다.

@synthesize missionName = _missionName;

보다 일반적으로 다음과 같습니다.

@synthesize propertyName = _ivarName;

78
자동 합성 속성을 사용하면 더 이상 필요하지 않습니다. Xcode는 씬 뒤에 _xxxx라는 ivar을 사용하여 @property xxxx를 합성합니다. 산뜻한.
LearnCocos2D

@ LearnCocos2D 안녕하세요! iOS 초보자는 여기에 명확히해야 할 것이 있습니다. 이 모든 시간 동안 내가 한 일은 property.h 파일 에 선언 하고 .m에서 나는 self그렇게 사용하여 액세스합니다 self.someProperty. 이것이 올바른 방법입니까? 아니면 코드에서 ivar을 사용해야합니까?
Isuru

ivar을 설정해도 속성 설정자가 실행되지 않습니다. 각각의 특정 상황에 적합한 지 여부를 결정합니다.
LearnCocos2D

멍청한 질문 : 왜 ivars를 직접 사용하지 않습니까? 왜 ivar을 보유 할 별도의 var를 선언해야합니까?
Allen

1
@Allen, 귀하의 질문을 올바르게 이해하면 선언하는 별도의 변수는 실제 변수에 대한 포인터입니다. 이것은 몇 가지 이유로 중요합니다 (내가 아는 것). 첫 번째로, 포인터를 함수에 전달할 때 값을 복제하지 않습니다. 단순히 사용할 값을 찾을 위치를 함수에 알려주는 것입니다. 이렇게하면 사용한 메모리를 낮게 유지할 수 있습니다 (또한 Java에서 찾을 수있는 '가비지 콜렉션'이없는 경우 중요한 메모리 할당 및 할당 해제에 도움이 됨)
David Sigley

18

가독성을위한 규칙 일 뿐이며 컴파일러에 특별한 작업을 수행하지 않습니다. 사람들이 프라이빗 인스턴스 변수 및 메소드 이름에이를 사용하는 것을 볼 수 있습니다. Apple은 실제로 밑줄을 사용하지 말 것을 권장합니다 (주의하지 않으면 수퍼 클래스에서 무언가를 무시할 수 있습니다). :)


19
내가 이해 한 바에 따르면, Apple은 메소드 이름에 밑줄 접두어를 사용하지 말 것을 권장하지만 (개인 메소드의 규칙으로 자체적으로 예약) 인스턴스 변수 이름에 대한 권장 사항은 없습니다.
Kelan

9
@Kelan 사실, Apple 은 다음과 같이 권장합니다 . "일반적으로 인스턴스 변수에 직접 액세스하지 말고 접근 자 메서드를 사용해야합니다 (init 및 dealloc 메서드에서 인스턴스 변수에 직접 액세스). 밑줄 (_)이있는 변수 이름 (예 : \ @implementation MyClass {BOOL _showsTitle;} "
dmirkitanov

iOS 개발자 라이브러리의 모든 샘플 코드에 ( ) 가 없으므로 Apple이 실제로 그렇게하도록 권장하지 않습니다. 애플은 또한 그것을 예약했다고 말한다. UIKit 등과 같은 자체 프레임 워크를 위해 내부적으로 사용한다는 뜻이다. 그래서 우리는 부주의하게 사용해서는 안된다. 그러나 나는 당신이 @kelan을 제공 한 링크에서 그것을 봅니다. 그들은 실제로 "개정 이력"에서 ( ) 를 사용하는 것이 "적합하다"고 말합니다 . 나는 우리가 원한다면 그것을 사용할 수 있다고 해석한다.
WYS

메소드 이름에 밑줄 접두어를 사용하지 말라고하는 Apple의 문서는 여기에 있습니다 .
ThomasW

9

내가 본 유일한 유용한 목적은 위에서 언급 한 것처럼 로컬 변수와 멤버 변수를 구별하는 것입니다.하지만 필수 규칙은 아닙니다. @property와 함께 사용하면 합성 문의 상세도가 증가 @synthesize missionName = _missionName;하고 모든 곳에서 추악합니다.

밑줄을 사용하는 대신 충돌하지 않는 메소드 내에 설명 변수 이름을 사용하십시오. 이들이 충돌 해야하는 경우, 메소드 내의 변수 이름은 여러 메소드가 사용할 수있는 멤버 변수가 아니라 밑줄로 표시되어야합니다 . 이것이 유용한 유일한 장소는 setter 또는 init 메소드입니다. 또한 @synthesize 문을 더 간결하게 만듭니다.

-(void)setMyString:(NSString*)_myString
{
    myString = _myString;
}

편집 : 자동 합성의 최신 컴파일러 기능을 사용하여 ivar에 밑줄을 사용합니다 (드문 경우에 자동 합성과 일치하도록 ivar을 사용해야하는 경우가 있습니다).


그것은 다른 길입니다. 개인 변수는 밑줄로 표시됩니다. 속성이 아닙니다. 그리고 그것들을 합성하면서 당신은 그것들을 결합시킵니다.
저스틴

내가 "개인 변수"대신 "멤버 변수"라고 부르는 것을 제외하고는 정확히 내가 설명한대로입니다.
Peter DeWeese

아야! 이것은 문제를 요구하고 있습니다 ... 자동 합성은 ivar를 _myString으로 만들어서 setter가 작동하지 않음을 의미합니다 (메서드 매개 변수에서 ivar을 알 수 없기 때문입니다).
geowar

애플이 자동 합성을 추가했을 때 마지막에 편집을 추가 한 이유입니다.
Peter DeWeese

5

그것은 실제로 아무것도 의미하지 않으며, 일부 사람들이 지역 변수와 멤버 변수를 구별하기 위해 사용하는 규칙 일뿐입니다.

오류는 aMission의 유형이 잘못된 것 같습니다. 그것의 선언은 무엇입니까?


IDE에서는 인텔리전스가 일반적입니다. 멤버 / 모듈 / 클래스 변수가 목록 맨 위에 표시됩니다. 또 다른 일반적인 previx는 "m_"
STW

1
의미가 없다면 위의 예와 같이 _missionName과 missionName 사이를 어떻게 전환 할 수 있습니까? 내 선언은 다음과 같습니다. Mission * aMission = [[Mission alloc] init]; aMission.missionName = @ "미션";
Atma

1
하나는 인스턴스 변수이고 다른 하나는 속성입니다. aMission.missionName과 같은 구문으로 인스턴스 변수에 액세스 할 수 없습니다. 해당 구문은 포인터에서 작동하지 않기 때문입니다.
Chuck

또한 Mission 객체에서 작업하려고하지만 missionName 속성으로 게시 한 인터페이스는 MissionCell입니다.
모간

2

이것은 합성 속성의 명명 규칙에만 해당됩니다.

.m 파일에서 변수를 합성하면 Xcode가 자동으로 _variable 지능을 제공합니다.


1

밑줄을 사용하면 self.member 구문 을 사용하지 않고 ivar 을 해결할 수 있을뿐만 아니라 변수가 ivar (밑줄 접두사로 인해)이거나 멤버 인수 (밑줄없이)를 알기 때문에 코드를 더 읽기 쉽게 만듭니다. ).

예:

- (void) displayImage: (UIImage *) image {

    if (image != nil) {
        // Display the passed image...
        [_imageView setImage: image];
    } else {
        // fall back on the default image...
        [_imageView setImage: _image];
    }
}

이 예제에서는 self.image (또는 [self image])의 사용을 비교하는 것이 좋습니다. self.image를 사용하는 것이 좋은 경우는 언제이고 _image를 사용하는 것이 좋은 경우는 언제입니까?
Boeckm

2
@Boeckm : 일반적으로 self.image속성에 액세스하는을 사용해야 합니다. 다른 변수를 호출 할 때 인스턴스 변수에 _image직접 액세스해야하는 유일한 시간 은 init메서드 내에 있고 dealloc메서드는 개체가 반 초기화되었거나 반 할당되지 않기 때문에 위험 할 수 있습니다.
피터 Hosey

1

self.variableName 대 _variablename에 대한 질문의 "마스터"항목 인 것 같습니다. 루프에 나를 던진 것은 .h에있는 것입니다.

...
@interface myClass : parentClass {
className *variableName;    // Note lack of _
}

@property (strong, nonatomic) className  *variableName;
...

이로 인해 self.variableName 및 _variableName이 .m에서 두 개의 고유 한 변수가됩니다. 내가 필요한 것은 :

...
@interface myClass : parentClass {
className *_variableName;    // Note presence of _
}

@property (strong, nonatomic) className  *variableName;
...

그런 다음 클래스의 .m에서 self.variableName과 _variableName은 동일합니다.

내가 아직도 분명하지 않은 것은 많은 예제가 여전히 작동하는 이유입니다.

레이


0

밑줄 대신 self.variable 이름을 사용하거나 밑줄없이 변수 또는 콘센트를 사용하도록 변수를 합성 할 수 있습니다.


2
당신은 단지 같은 클래스에서 변수가 필요하면 그때하는 .m 파일에 자신을 선언 그것은 당신이 자신이나 밑줄없이 호출 할 수 있습니다
Ansal 안토니

0

다른 대답 _variable에서 빠지면 사용 하면 variable(아마도 의도 된) 속성이 아니라 ivar 를 실수로 입력 하고 액세스 할 수 없습니다.

컴파일러는 당신이 중 하나를 사용하도록 강제 self.variable하거나 _variable. 밑줄을 사용하면을 입력 할 수 없으므로 variable프로그래머 오류가 줄어 듭니다.

- (void)fooMethod {

    // ERROR - "Use of undeclared identifier 'foo', did you mean '_foo'?"
    foo = @1;

    // So instead you must specifically choose to use the property or the ivar:

    // Property
    self.foo = @1;

    // Ivar
    _foo = @1;

}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.