[objective-c] @ 클래스 대 #import

클래스 A가 ClassB 헤더를 포함해야하고 클래스 B가 순환 포함을 피하기 위해 클래스 A 헤더를 포함 해야하는 경우 이벤트에서 순방향 클래스 선언을 사용해야한다는 것을 이해합니다. 또한 포함이 한 번만 발생하도록 #import간단한 것임을 이해합니다 ifndef.

내 질문은 이것입니다 : 하나는 언제 사용 #import하고 언제 사용 @class합니까? 때로는 @class선언을 사용 하면 다음과 같은 일반적인 컴파일러 경고가 표시됩니다.

warning: receiver 'FooController' is a forward class and corresponding @interface may not exist.

@class전진 선언을 제거 #import하고 컴파일러가 나에게주는 경고를 침묵시키는 것을 던지는 것보다 이것을 이해 하고 싶습니다.



답변

이 경고가 표시되면

경고 : 수신자 ‘MyCoolClass’는 순방향 클래스이며 해당 @ 인터페이스가 존재하지 않을 수 있습니다

#import파일 이 필요 하지만 구현 파일 (.m)에서이를 수행하고 @class헤더 파일에서 선언을 사용할 수 있습니다.

@class(보통) #import파일 의 필요성을 제거하지 않고 정보가 유용한 곳으로 요구 사항을 더 가깝게 이동시킵니다.

예를 들어

이라고 말하면 @class MyCoolClass컴파일러는 다음과 같은 것을 볼 수 있습니다.

MyCoolClass *myObject;

MyCoolClass유효한 클래스 이외의 것에 대해 걱정할 필요가 없으며 포인터 (실제로는 포인터)를위한 공간을 예약해야합니다. 따라서 헤더 @class에서 시간의 90 %이면 충분합니다.

그러나 myObject의 멤버 를 작성하거나 액세스 해야하는 경우 컴파일러에게 해당 메소드가 무엇인지 알려 주어야합니다. 이 시점에서 (아마도 구현 파일에서) #import "MyCoolClass.h"컴파일러에게 “이것은 클래스입니다”이외의 추가 정보를 알려 주어야합니다 .


답변

세 가지 간단한 규칙 :

  • #import헤더 파일 ( .h파일) 에는 수퍼 클래스 및 채택 된 프로토콜 만 있습니다.
  • #import모든 클래스와 프로토콜의 경우 구현시 메시지를 .m파일로 보냅니다 .
  • 다른 모든 것에 대한 선언을 전달하십시오.

구현 파일에서 선언을 전달하면 뭔가 잘못되었을 수 있습니다.


답변

ADC 에 대한 Objective-C 프로그래밍 언어 문서를보십시오

클래스 정의하기 섹션에서 | 이것이 수행되는 이유를 설명하는 클래스 인터페이스 :

@class 지시문은 컴파일러와 링커에서 볼 수있는 코드의 양을 최소화하므로 클래스 이름을 전달하는 가장 간단한 방법입니다. 간단하기 때문에 다른 파일을 가져 오는 파일을 가져올 때 발생할 수있는 잠재적 인 문제를 피할 수 있습니다. 예를 들어, 한 클래스가 다른 클래스의 정적으로 유형이 지정된 인스턴스 변수를 선언하고 두 인터페이스 파일이 서로 가져 오면 클래스가 올바르게 컴파일되지 않을 수 있습니다.

이게 도움이 되길 바란다.


답변

필요한 경우 헤더 파일에 전달 선언을 #import사용하고 구현에 사용중인 클래스의 헤더 파일을 사용하십시오. 즉, 항상 #import구현에 사용하는 파일이며 헤더 파일에서 클래스를 참조 해야하는 경우 전달 선언도 사용하십시오.

이에 대한 예외#import헤더 파일에서 상속하는 클래스 또는 공식 프로토콜 이어야한다는 것입니다 (이 경우 구현에서 가져올 필요가 없습니다).


답변

일반적인 방법은 헤더 파일에서 @class를 사용하지만 (여전히 #supersuperclass를 가져와야 함) 구현 파일에서 #import를 사용해야합니다. 이것은 순환 포함을 피할 것이고, 그것은 효과가 있습니다.


답변

또 다른 장점 : 빠른 컴파일

헤더 파일을 포함하는 경우 헤더 파일을 변경하면 현재 파일도 컴파일되지만 클래스 이름이로 포함 된 경우에는 그렇지 않습니다 @class name. 물론 소스 파일에 헤더를 포함해야합니다


답변

내 질문은 이것입니다. 언제 #import를 사용하고 언제 @class를 사용합니까?

간단한 대답 : 귀하 #import또는 #include신체적 의존성이있을 때. 그렇지 않으면, 당신은 앞으로 선언을 사용 ( @class MONClass, struct MONStruct, @protocol MONProtocol).

신체적 의존성에 대한 일반적인 예는 다음과 같습니다.

  • C 또는 C ++ 값 (포인터 또는 참조는 물리적 종속성이 아님) CGPointivar 또는 속성으로 a 를 사용하는 경우 컴파일러에서의 선언을 확인해야합니다 CGPoint.
  • 당신의 슈퍼 클래스.
  • 사용하는 방법.

@class 선언을 사용하는 경우 때때로 다음과 같은 일반적인 컴파일러 경고가 표시됩니다. “경고 : 수신자 ‘FooController’는 순방향 클래스이며 해당 @interface가 없을 수 있습니다.”

컴파일러는 이와 관련하여 실제로 매우 관대합니다. 힌트 (예 : 위와 같은)를 제거하지만 스택을 무시하고 #import올바르게 처리 하지 않으면 스택을 쉽게 휴지통에 버릴 수 있습니다 . 비록 (IMO)하더라도 컴파일러는 이것을 강제하지 않습니다. ARC에서 컴파일러는 참조 카운팅을 담당하므로 더 엄격합니다. 무슨 일이 일어나는지는 컴파일러가 알 수없는 메소드를 만나면 기본값으로 돌아갑니다. 모든 반환 값과 매개 변수는로 가정합니다 id. 따라서 코드베이스의 모든 경고를 근절해야합니다. 이는 물리적 종속성으로 간주되어야하기 때문입니다. 이것은 선언되지 않은 C 함수를 호출하는 것과 유사합니다. C를 사용하면 매개 변수는로 간주됩니다 int.

전방 선언을 선호하는 이유는 최소한의 의존성이 있기 때문에 요인으로 빌드 시간을 줄일 수 있기 때문입니다. 정방향 선언을 사용하면 컴파일러는 이름이 있음을 확인하고 물리적 종속성이 없을 때 클래스 선언이나 모든 종속성을 보지 않고도 프로그램을 올바르게 구문 분석하고 컴파일 할 수 있습니다. 깨끗한 빌드는 시간이 덜 걸립니다. 증분 빌드는 시간이 덜 걸립니다. 물론, 필요한 모든 헤더가 결과적으로 모든 번역에 표시되도록하는 데 약간의 시간이 더 걸리지 만, 빌드 시간이 단축됩니다 (프로젝트가 작지 않다고 가정).

#import또는 #include대신 사용 하면 필요한 것보다 컴파일러에서 더 많은 작업을 수행합니다. 복잡한 헤더 종속성도 도입하고 있습니다. 이것을 무차별 알고리즘에 비유 할 수 있습니다. 당신이 때 #import, 당신은 메모리, 디스크 분석하고 소스를 컴파일하는 I / O 및 CPU를 많이 필요로 불필요한 정보의 톤에 드래그하고 있습니다.

ObjC는 NSObject타입이 결코 값이 아니기 때문에 의존성 측면에서 C 기반 언어에 이상적입니다. NSObject타입은 항상 참조 카운트 포인터입니다. 따라서 물리적 종속성이 거의 없기 때문에 프로그램의 종속성을 적절하게 구성하고 가능한 경우 앞으로 컴파일하면 엄청나게 빠른 컴파일 시간을 피할 수 있습니다. 종속성을 추가로 최소화하기 위해 클래스 확장에서 속성을 선언 할 수도 있습니다. 이는 대규모 시스템의 경우 큰 보너스입니다. 대규모 C ++ 코드베이스를 개발 한 경우의 차이점을 알게 될 것입니다.

따라서 가능한 경우 전달을 사용하고 #import물리적 의존성이있는 곳을 사용하는 것이 좋습니다 . 물리적 의존성을 의미하는 경고 또는 다른 경고가 표시되면 모두 수정하십시오. 수정 사항은 #import구현 파일에 있습니다.

라이브러리를 빌드 할 때 일부 인터페이스를 그룹으로 분류 할 #import수 있습니다.이 경우 물리적 종속성이 도입 된 라이브러리 (예 :)가 #import <AppKit/AppKit.h>됩니다. 이것은 의존성을 유발할 수 있지만, 라이브러리 관리자는 종종 필요에 따라 물리적 의존성을 처리 할 수 ​​있습니다. 기능을 도입하면 빌드에 미치는 영향을 최소화 할 수 있습니다.