문제

저는 Obj-c와 Cocoa에서 수년간의 경험을 갖고 있지만 이제 막 다시 Obj-C 2.0 등의 발전에 대해 알아보고 있습니다.

최신 런타임과 속성 선언 등에 대해 알아보려고 합니다.나를 조금 혼란스럽게 만드는 한 가지는 iVar를 암시적으로 생성할 수 있는 최신 런타임의 기능입니다.물론 이는 코드에서 값에 액세스하려면 항상 self.property를 사용해야 함을 의미합니다.

그러나 init* 및 dealloc(GC를 사용하지 않는다고 가정) 메서드에서는 iVar를 직접(현재 런타임에서) 사용해야 합니다.

질문은 다음과 같습니다.

  1. Modern Runtime의 init* 및 dealloc에서 속성 접근자를 사용해야 합니까?

  2. 그렇다면, 왜 다른가요?컴파일러가 iVar를 볼 수 없기 때문입니까?

  3. 접근자를 재정의해야 하는 경우 런타임에 정의될 해당 iVar에 계속 액세스할 수 있습니까? 아니면 런타임에서 사용할 실제 iVar를 정의해야 합니까?

  4. 다시, 합성된 iVar에 액세스할 수 있다면, init* 및 dealloc 메소드에 대해 이 작업을 계속할 수 없는 이유는 무엇입니까?

문서를 여러 번 읽었지만 이 모든 것에 대해 약간 모호해 보였고 코딩을 계속할지 결정하기 위해 문서를 잘 이해하고 있는지 확인하고 싶습니다.

내 질문이 명확해지기를 바랍니다.


테스트 요약:

  1. 레거시에서 ivar를 선언하지 않으면 컴파일러가 완전히 불행해집니다.

  2. 당신이 사용하는 경우 #ifndef __OBJC2__ 레거시 컴파일러의 ivar 주변은 행복하며 ivar를 직접 사용하거나 속성으로 사용할 수 있습니다.

  3. 최신 런타임에서는 ivar를 정의되지 않은 상태로 두고 속성으로 액세스할 수 있습니다.

  4. 최신 런타임에서 선언 없이 ivar에 직접 액세스하려고 하면 컴파일 중에 오류가 발생합니다.

  5. @private 물론 ivar를 선언하면 레거시 및 최신 버전 모두에서 ivar에 직접 액세스할 수 있습니다.

지금 당장은 앞으로 나아갈 수 있는 깔끔한 방법을 제공하지 않습니까?

도움이 되었습니까?

해결책

현재 (OS X 10.5/GCC 4.0.1) 컴파일러에서는 런타임 합성 IVAR에 직접 액세스 할 수 없습니다. Greg Parker, OS X 런타임 엔지니어 중 한 명이 이것 코코아 데브 목록의 길 (2009 년 3 월 12 일) :

현재 컴파일러에서는 할 수 없습니다. 미래의 컴파일러는이 문제를 해결해야합니다. 그 동안 명시 적 @private ivars를 사용하십시오. @private ivar는 계약의 일부로 간주되어서는 안됩니다. 이것이 바로 @private가 컴파일러 경고 및 링커 오류에 의해 시행되는 의미입니다.

그리고 새 런타임의 .M 파일에서 인스턴스 변수를 명시 적으로 선언 할 수있는 방법이없는 이유는 무엇입니까?

세 가지 이유 : (1) 해결해야 할 몇 가지 사소한 디자인 세부 사항이 있습니다. (2) 컴파일러 엔지니어 시간은 제한되어 있으며 (3) @private IVARS는 일반적으로 충분합니다.

따라서 지금은 도트 노트를 사용하여 속성에 액세스해야합니다. init 그리고 dealloc. 이것은이 경우 직접 IVAR을 사용하는 모범 사례에 위배되지만 주변에는 방법이 없습니다. 런타임 상속 된 IVAR (및 성능 이점)을 사용하는 것이 대부분의 경우이를 능가한다는 것을 알았습니다. IVAR에 직접 액세스 해야하는 경우 Greg Parker가 제안한대로 @Private IVAR을 사용할 수 있습니다 (명시 적으로 선언하고 런타임으로 인한 IVAR을 혼합하지 못하게하는 것은 없습니다).

업데이트 OS X 10.6을 사용하면 64 비트 런타임은 합성 된 IVAR을 통해 직접 액세스 할 수 있습니다. self->ivar.

다른 팁

인스턴스 변수 자체는 최신 런타임에서만 합성 될 수 있고 (32 비트 또는 프리-레오파드에서 @Interface에서 선언해야 함) IVAR을 선언하는 것이 가장 안전하거나 가장 휴대용입니다.

  • Init*에서 Property Accessor를 사용하고 현대적인 런타임과 함께 Dealloc을 사용해야합니까?

내 경험의 규칙은 "아마도"입니다 -init*, 그리고 "보통"을 위해 -dealloc.

객체를 초기화 할 때 IVAR의 값을 올바르게 복사/유지해야합니다. 부동산 세터에 초기화에 부적절한 부작용이 없다면 부동산이 제공하는 추상화를 확실히 재사용하십시오.

객체를 거래 할 때는 객체를 퇴원하려고하지만 새로운 개체를 출시하려고하지만 새 개체를 저장하지는 않습니다. 이 작업을 수행하는 쉬운 방법은 속성을 NIL로 설정하는 것입니다.myObject.myIvar = nil), 기본적으로 호출합니다 [myObject setMyIvar:nil]. NIL에 대한 메시지는 무시되므로 이것에 위험이 없습니다. 그러나 [myivar 릴리스]가 과잉입니다. 일반적으로 필요한 전부입니다. 일반적으로, 거래가 변수를 설정하는 것과 다르게 행동 해야하는 상황에서 속성 (또는 직접 세터)을 사용하지 마십시오.

Init/Dealloc에서 속성 액세서를 사용하는 것에 대한 Ejames의 주장을 이해할 수 있지만, 플립 사이드는 속성 동작을 변경하는 경우 (예 : 보유에서 복사로 변경하거나, 유지하지 않고 할당) 사용하지 않는다는 것입니다. Init 또는 그 반대에서도 동작도 동기화되지 않을 수 있습니다. IVAR을 초기화하고 수정하는 경우 동일하게 행동 해야하는 경우 속성 액세서를 사용하십시오.

  • 그렇다면 왜 다른가요? 컴파일러가 IVAR을 볼 수 없기 때문입니까?

최신 런타임은 클래스 크기와 레이아웃을보다 지능적으로 다루므로 서브 클래스를 다시 컴파일하지 않고도 IVAR의 레이아웃을 변경할 수 있습니다. 또한 해당 속성의 이름과 유형에서 원하는 IVAR의 이름과 유형을 추론 할 수 있습니다. 그만큼 Objective-C 2.0 런타임 프로그래밍 안내서 더 많은 정보가 있지만 다시, 세부 사항이 얼마나 깊이 설명되었는지 모르겠습니다.

  • 액세서를 무시 해야하는 경우 런타임에 정의 될 IVAR에 액세스 할 수 있습니까? 아니면 런타임이 사용할 실제 IVAR을 정의해야합니까?

나는 이것을 테스트하지 않았지만, 당신은 실제로 만들어진 IVAR에 액세스 할 수 있다고 생각합니다. 컴파일러가 불평할지 여부는 확실하지 않지만 불만없이 IVAR을 합성 할 수 있기 때문에 합성 된 IVAR에 대해 알 수있을 정도로 똑똑하고 이름으로 언급 할 수있을 것입니다.

  • 다시 한 번, 합성 된 IVAR에 액세스 할 수 있다면 왜 INIT* 및 DENCELLOC 방법에 대해 계속 할 수 없습니까?

인스턴스가 할당 된 후 언제든지 재산 및/또는 IVAR에 액세스 할 수 있어야합니다.

거기 있습니다 또 다른 질문입니다 비슷한 정보를 사용하지만 중복은 아닙니다.

결론 대상 C 2.0 문서, 인용 마크 베시의 대답 다음과 같다:

런타임에 의존하는 동작에는 차이가 있습니다 ( "런타임 차이"참조) :

레거시 런타임의 경우 인스턴스 변수는 이미 @interface 블록에 선언되어야합니다. 속성과 동일한 이름과 호환 유형의 인스턴스 변수가 존재하는 경우,이 제품이 사용됩니다. 즉, 컴파일러 오류가 발생합니다.

최신 런타임의 경우 인스턴스 변수가 필요에 따라 합성됩니다. 동일한 이름의 인스턴스 변수가 이미 존재하는 경우 사용됩니다.

내 이해는 다음과 같습니다.

속성 액세서를 사용해서는 안됩니다 init* 그리고 dealloc 방법, 레거시 런타임에서 사용해서는 안되는 이유와 같은 이유로 : 나중에 속성 메소드를 무시하고 수행하지 않아야 할 일을하면 잠재적 오류가 발생합니다. init* 또는 dealloc.

IVAR을 합성 할 수 있어야합니다 그리고 속성 메소드를 다음과 같이 무시합니다.

@interface SomeClass
{
}
@property (assign) int someProperty;
@end

@implementation SomeClass
@synthesize someProperty; // this will synthesize the ivar
- (int)someProperty { NSLog(@"getter"); return someProperty; }
- (void)setSomeProperty:(int)newValue
{
    NSLog(@"setter");
    someProperty = newValue;
}
@end

그것은 당신이 당신의 합성 IVAR에 액세스 할 수 있다고 생각하게합니다. init* 그리고 dealloc 방법도. 내가 생각할 수있는 유일한 gotcha는 @synthesize 선이 와야 할 수도 있습니다 ~ 전에 당신의 정의 init* 그리고 dealloc 소스 파일의 메소드.

결국, 인터페이스에서 IVARS를 선언 한 것이 여전히 작동하기 때문에 여전히 가장 안전한 내기입니다.

나는 같은 문제에 빠지고있다. 합성 된 인스턴스 변수에 액세스 할 수없는 방법은 다음과 같습니다.

공개 헤더

@interface MyObject:NSObject {
}
@property (retain) id instanceVar;
@property (retain) id customizedVar;
@end

개인 헤더 / 구현

@interface MyObject()
@property (retain) id storedCustomizedVar;
@end

@implementation MyObject
@synthesize instanceVar, storedCustomizedVar;
@dynamic customizedVar;

- customizedVar {
  if(!self.storedCustomizedVar) {
    id newCustomizedVar;
    //... do something
    self.storedCustomizedVar= newCustomizedVar;
  }
  return self.storedCustomizedVar;
}

- (void) setCustomizedVar:aVar {
  self.storedCustomizedVar=aVar;
}

@end

그렇게 우아하지는 않지만 적어도 공개 헤더 파일을 깨끗하게 유지합니다.

KVO를 사용하는 경우 CustomizedVar를 StoredCustomizedVar의 종속 키로 정의해야합니다.

저는 Obj-C를 처음 접했지만(프로그래밍은 아님) 이 주제 때문에 혼란스럽기도 했습니다.

제가 걱정되는 점은 속성 대신 iVar를 무심코 사용하는 것이 상대적으로 쉬운 것 같습니다.예를 들면 다음과 같습니다.

myProp = someObject;

대신에

self.myProp = someObject;

물론 이것은 "사용자" 오류이지만 일부 코드에서는 실수로 발생하기가 매우 쉽고 유지되거나 원자적인 속성의 경우 문제가 발생할 수 있습니다.

이상적으로는 생성 시 속성 이름에 일부 패턴을 적용하도록 런타임을 얻을 수 있기를 원합니다. 어느 iVar.예:항상 "_" 접두사를 붙이세요.

실제로는 현재 이 작업을 수동으로 수행하고 있습니다. ivar를 명시적으로 선언하고 의도적으로 속성과 다른 이름을 지정합니다.나는 이전 스타일의 'm' 접두사를 사용하므로 내 속성이 "myProp"이면 내 iVar는 "mMyProp"이 됩니다.그런 다음 @synthesize myProp = mMyProp을 사용하여 둘을 연결합니다.

제가 인정하는 것은 약간 서투르고 약간의 추가 입력이 필요하지만 코드에서 좀 더 명확하게 구분할 수 있는 것이 가치가 있는 것 같습니다.물론 여전히 잘못 입력하여 mMyProp = someObject를 입력할 수 있지만 'm' 접두어가 내 오류를 알려줄 것으로 기대합니다.

속성만 선언하고 컴파일러/런타임이 나머지 작업을 수행하도록 하면 훨씬 더 기분이 좋을 것입니다. 하지만 코드가 많을 때 수동 규칙을 계속 따라야 한다면 그런 식으로 실수를 하게 될 것이라고 직감적으로 말합니다. 초기화/dealloc용.

물론 내가 잘못할 수 있는 다른 일들도 많이 있지만…

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top