@수업 대.#수입의
클래스 A는 클래스 B 헤더를 포함해야 하고 클래스 B는 순환 포함을 피하기 위해 클래스 A 헤더를 포함해야 하는 경우에 포워드 클래스 선언을 사용해야 하는 것으로 알고 있습니다.저는 또한 이해합니다.#import
한 순한입니다.ifndef
포함이 한 번만 발생하도록 합니다.
제 질문은 다음과 같습니다. 언제사용까니를 사용합니까?#import
그리고 언제 사용합니까?@class
가끔 내가 사용한다면,@class
나는 인 컴파일러 : 언다과, 나같일인컴반봅경니다고를:
warning: receiver 'FooController' is a forward class and corresponding @interface may not exist.
단지 그것을 제거하는 것과 비교해서, 이것을 정말로 이해하고 싶습니다.@class
와 공 #import
컴파일러가 나에게 주는 경고를 잠재우기 위해.
이 경고가 표시되는 경우:
경고: 수신기 'MyCoolClass'가 정방향 클래스이며 해당 @interface가 존재하지 않을 수 있습니다.
할 필요가 있습니다.#import
에서 이 작업을 할 수 . " " " " 를 사용하십시오." 를 하십시오.@class
헤더 파일에 선언이 있습니다.
@class
는 (#import
파일은 정보가 유용한 곳으로 요구사항을 이동시킬 뿐입니다.
예를들면
.@class MyCoolClass
컴파일러는 다음과 같은 것을 볼 수 있다는 것을 알고 있습니다.
MyCoolClass *myObject;
그것은 다른 것에 대해 걱정할 필요가 없습니다.MyCoolClass
는 유효한 클래스이며, 해당 클래스에 대한 포인터를 위한 공간을 예약해야 합니다(실제로는 포인터일 뿐입니다.그서래, 당의머에글리,@class
90%의 시간으로 충분합니다.
그러나, 파일을 만들거나 액세스해야 하는 경우myObject
의 멤버들, 당신은 컴파일러에게 그 방법들이 무엇인지 알려야 할 것입니다. 구현 파일에 입니다.)#import "MyCoolClass.h"
컴파일러에게 단순히 "이것은 클래스" 이상의 추가 정보를 제공합니다.
세 가지 간단한 규칙:
- .
#import
파일에서 클래스된 프로토콜( 더파일에프및콜로토채헤된택슈퍼래스클서,(▁the콜토).h
파일). #import
할 때 경우(" 든클래및프구을보때다냅메니를모시지현할콜로토스▁all보다,냅▁in니모를▁to메").m
파일).- 다른 모든 것에 대한 선언을 전달합니다.
구현 파일에서 포워드 선언을 수행하면 잘못된 작업을 수행할 수 있습니다.
ADC의 Objective-C 프로그래밍 언어 설명서를 참조하십시오.
클래스 | 클래스 인터페이스 정의 섹션에서 이 작업이 수행되는 이유를 설명합니다.
@class 디렉티브는 컴파일러와 링커에 의해 표시되는 코드의 양을 최소화하므로 클래스 이름의 포워드 선언을 제공하는 가장 간단한 방법입니다.따라서 다른 파일을 가져오는 파일을 가져올 때 발생할 수 있는 잠재적인 문제를 방지할 수 있습니다.예를 들어, 한 클래스가 정적으로 형식화된 다른 클래스의 인스턴스 변수를 선언하고 두 개의 인터페이스 파일을 서로 가져오면 두 클래스 모두 올바르게 컴파일할 수 없습니다.
하고, "forward declaration"을 사용합니다.#import
구현에서 사용 중인 모든 클래스의 헤더 파일.다시 말해서, 당신은 항상#import
구현에 사용 중인 파일과 헤더 파일의 클래스를 참조해야 하는 경우 전달 선언도 사용합니다.
이에 대한 예외는 당신이 해야 한다는 것입니다.#import
헤더 파일에서 상속할 클래스 또는 공식 프로토콜(이 경우 구현에서 가져올 필요가 없음).
일반적으로 헤더 파일에서는 @class를 사용하고 구현 파일에서는 #import를 수행해야 합니다.이렇게 하면 순환적인 포함을 피할 수 있고 효과가 있습니다.
또 다른 이점:빠른 컴파일
파일을 , 이 헤더파포는경우하, 함파변클만이지래컴스다다로 포함되는 .@class name
은 소스 시켜야 할 것입니다.
제 질문은 이것입니다.#import는 언제 사용하고 @class는 언제 사용합니까?
간단한 대답:너#import
또는#include
신체적 의존성이 있을 때.그렇지 선언그렇니다지않합사용선전을언달으면다니사▁(ations")을 합니다.@class MONClass
,struct MONStruct
,@protocol MONProtocol
).
다음은 물리적 의존성의 몇 가지 일반적인 예입니다.
- 임의의 C 또는 C++ 값(포인터 또는 참조는 물리적 종속성이 아닙니다).만약 당신이 가지고 있다면.
CGPoint
ivar 또는 속성으로서 컴파일러는 다음의 선언을 볼 필요가 있습니다.CGPoint
. - 너의 슈퍼클래스.
- 사용하는 방법입니다.
가끔 @class 선언을 사용하면 다음과 같은 일반적인 컴파일러 경고가 나타납니다. "warning: receiver 'FooController'는 포워드 클래스이며 해당 @interface는 존재하지 않을 수 있습니다."
컴파일러는 이 점에서 사실 매우 관대합니다.힌트(위와 같은)를 삭제하지만 무시하고 무시하지 않으면 스택을 쉽게 폐기할 수 있습니다.#import
(이를 .IMO를 사용해야 하지만 컴파일러는 이 작업을 수행하지 않습니다.ARC에서 컴파일러는 참조 카운트를 담당하기 때문에 더 엄격합니다.사용자가 호출하는 알 수 없는 메서드를 발견하면 컴파일러가 기본값으로 되돌아갑니다.는 모든반값매변개다음같가과다이니정됩수로 가정합니다.id
따라서 이것은 물리적 종속성으로 간주되어야 하므로 코드베이스에서 모든 경고를 제거해야 합니다.이는 선언되지 않은 C 함수를 호출하는 것과 유사합니다.는 C 경 모 다 음 같 가 정 됩 니 다 이 과 우 의 수 가정됩니다.int
.
포워드 선언을 선호하는 이유는 종속성이 최소화되기 때문에 요소별로 빌드 시간을 줄일 수 있기 때문입니다.포워드 선언을 사용하면 컴파일러는 이름이 있는 것을 보고, 물리적 종속성이 없을 때 클래스 선언이나 모든 종속성을 보지 않고 프로그램을 올바르게 구문 분석하고 컴파일할 수 있습니다.클린 빌드는 시간이 더 적게 걸립니다.증분 빌드는 시간이 더 적게 걸립니다.결과적으로 모든 번역에 필요한 모든 헤더가 표시되도록 하는 데 시간을 좀 더 할애하게 됩니다. 하지만 이를 통해 빌드 시간을 단축할 수 있습니다(프로젝트가 작지 않다고 가정할 때).
사용하는 경우#import
또는#include
대신, 당신은 컴파일러에게 필요한 것보다 훨씬 더 많은 작업을 던지고 있습니다.또한 복잡한 헤더 의존성을 도입하고 있습니다.이것을 브루트 포스 알고리즘에 비유할 수 있습니다.이 신이당 때.#import
소스를 구문 분석하고 컴파일하는 데 많은 메모리, 디스크 I/O 및 CPU가 필요한 불필요한 정보를 끌어 들이고 있습니다.
ObjC는 의존성과 관련하여 C 기반 언어에 매우 이상적입니다.NSObject
값이 . -- 은절값아이닙다니대형식▁--▁--다▁types니▁are아닙. --NSObject
countedpointers.type은 항상 reference counted pointers입니다.따라서 필요한 물리적 의존성이 거의 없기 때문에 프로그램의 종속성을 가능한 한 앞으로 적절하게 구성하면 매우 빠른 컴파일 시간을 사용할 수 있습니다.클래스 확장에서 속성을 선언하여 종속성을 더욱 최소화할 수도 있습니다.이것은 큰 시스템에 큰 보너스입니다. 만약 당신이 큰 C++ 코드베이스를 개발해본 적이 있다면 당신은 그것이 어떤 차이를 만들어내는지 알 것입니다.
따라서 가능한 경우 포워드를 사용하고 다음을 수행하는 것이 좋습니다.#import
물리적 의존성이 있는 곳.만약 여러분이 신체적 의존성을 암시하는 경고나 다른 경고를 본다면, 그것들을 모두 고쳐라.은 결은해책은.#import
구현 파일에 있습니다.
라이브러리를 빌드할 때 일부 인터페이스를 그룹으로 분류할 수 있습니다. 이 경우에는#import
물적의도라예이입브러리된이성존리예▁where(:리러▁that▁library):#import <AppKit/AppKit.h>
이렇게 하면 종속성이 발생할 수 있지만 라이브러리 관리자는 필요에 따라 물리적 종속성을 처리할 수 있습니다. 기능을 도입하면 빌드에 미치는 영향을 최소화할 수 있습니다.
"Do do it this way"는 많이 보이지만 "Why?"에 대한 답은 전혀 보이지 않습니다.
그렇다면 왜 헤더에서는 @class를 사용하고 구현에서는 #import만 사용해야 합니까?항상 @class 및 #import를 수행해야 하므로 작업이 두 배로 늘어납니다.당신이 상속을 이용하지 않는 한.이 경우 단일 @class에 대해 여러 번 #importing을 수행하게 됩니다.그런 다음 선언에 대한 액세스가 더 이상 필요하지 않다고 갑자기 결정한 경우 여러 개의 다른 파일에서 제거해야 합니다.
#import의 특성상 동일한 파일을 여러 번 가져오는 것은 문제가 되지 않습니다.성능을 컴파일하는 것도 문제가 되지 않습니다.만약 그렇다면, 우리가 가지고 있는 거의 모든 헤더 파일에서 #importing Cocoa/Cocoa.h 등을 하지는 않을 것입니다.
이렇게 하면
@interface Class_B : Class_A
즉, Class_A를 Class_B로 상속하고 Class_B에서 Class_A의 모든 변수에 액세스할 수 있습니다.
만약 우리가 이것을 한다면,
#import ....
@class Class_A
@interface Class_B
여기서 우리는 프로그램에서 Class_A를 사용한다고 말하지만 Class_B에서 Class_A 변수를 사용하려면 .m 파일에서 #Class_A를 가져와야 합니다(개체를 만들고 그것의 함수와 변수를 사용합니다).
파일 종속성 &#import & @class에 대한 자세한 내용은 다음을 확인하십시오.
http://qualitycoding.org/file-dependencies/ 그것은 좋은 기사입니다.
기사의 요약
헤더 파일로 가져오기:
- #상속하고 있는 슈퍼클래스와 구현하고 있는 프로토콜을 가져옵니다.
- 마스터 헤더가 있는 프레임워크에서 가져온 경우를 제외하고 다른 모든 항목을 전달합니다.
- 다른 #imports를 모두 제거합니다.
- 종속성을 줄이기 위해 자체 헤더에 프로토콜을 선언합니다.
- 포워드 선언이 너무 많습니까?클래스가 큽니다.
구현 파일로 가져오기:
- 사용하지 않는 cruft #import를 제거합니다.
- 메서드가 다른 개체로 위임하고 반환되는 내용을 반환하는 경우 #가져오기 대신 해당 개체를 포워드 선언합니다.
- 모듈을 포함하면 연속적인 종속성 수준 이후의 수준을 포함해야 하는 경우 라이브러리가 될 클래스 집합이 있을 수 있습니다.마스터 헤더가 있는 별도의 라이브러리로 빌드하여 모든 항목을 사전 빌드된 단일 청크로 가져올 수 있습니다.
- #가져오기가 너무 많습니까?클래스가 큽니다.
제가 발전할 때, 저는 결코 저에게 문제를 일으키지 않는 단 세 가지를 염두에 두고 있습니다.
- 수퍼 클래스 가져오기
- 부모 클래스 가져오기(자녀 및 부모가 있는 경우)
- 프로젝트 외부로 클래스 가져오기(예: 프레임워크 및 라이브러리)
다른 모든 클래스(프로젝트 자체의 하위 클래스 및 하위 클래스)에 대해서는 정방향 클래스를 통해 선언합니다.
아직 가져오지 않은 변수 또는 헤더 파일의 속성을 선언하려고 하면 컴파일러가 이 클래스를 모른다는 오류가 발생합니다.
당신의 첫 번째 생각은 아마도#import
그것.
경우에 따라 문제가 발생할 수 있습니다.
예를 들어 여러 번 가져오면 안 되기 때문에 헤더 파일이나 구조체 등에 C-method를 여러 번 구현하는 경우가 있습니다.
그러므로 당신은 컴파일러에게 다음과 같이 말할 수 있습니다.@class
:
당신이 그 수업을 모른다는 것을 알지만, 그것은 존재합니다.다른 곳에서 가져오거나 구현할 예정입니다.
이것은 기본적으로 컴파일러에게 이 클래스가 구현될지는 확실하지 않지만 종료하고 컴파일하라고 말합니다.
일적으사다니용합을 사용할 입니다.#import
아침에@class
.h 파일에 있습니다.
선언을 컴파일러에 오류가 표시되지 않도록 전달합니다.
컴파일러는 헤더 파일에서 선언할 이름을 가진 클래스가 있다는 것을 알게 됩니다.
컴파일러가 해당 클래스의 구현을 알아야 하는 방식으로 해당 클래스를 사용할 경우에만 컴파일러가 불만을 제기합니다.
예:
- 이것은 당신이 그것으로부터 당신의 수업을 이끌어낼 것이거나 혹은
- 해당 클래스의 개체를 구성원 변수로 사용하려는 경우(희귀하지만).
당신이 그것을 단지 포인터로 사용할 것이라면 불평하지 않을 것입니다.물론 객체를 인스턴스화하려면 클래스 내용을 알아야 하므로 구현 파일(해당 클래스의 객체를 인스턴스화하는 경우)에 #가져와야 합니다.
참고: #import는 #include와 다릅니다.이것은 순환 수입이라고 불리는 것이 없다는 것을 의미합니다.import는 컴파일러가 특정 파일에서 정보를 검색하기 위한 일종의 요청입니다.해당 정보를 이미 사용할 수 있는 경우 컴파일러는 이를 무시합니다.
그냥 이것을 시도해 보세요. A.h는 B.h로, B.h는 A.h로 수입합니다.문제나 불만은 없을 것이고 잘 작동할 것입니다.
@class 사용 시기
@class는 헤더의 헤더를 가져오지 않으려는 경우에만 사용합니다.이것은 당신이 그 수업이 무엇이 될지조차 신경 쓰지 않는 경우일 수 있습니다.해당 클래스에 대한 머리글이 아직 없을 수도 있습니다.
예를 들어 두 개의 라이브러리를 작성하는 경우를 들 수 있습니다.A라고 부르는 하나의 클래스가 하나의 라이브러리에 존재합니다.이 라이브러리에는 두 번째 라이브러리의 헤더가 포함되어 있습니다.해당 헤더에 A의 포인터가 있을 수 있지만 사용할 필요가 없을 수도 마찬가지입니다.라이브러리 1을 아직 사용할 수 없는 경우 @class를 사용하면 라이브러리 B가 차단되지 않습니다.하지만 A.h를 가져오려면 라이브러리 2의 진행이 차단됩니다.
@class를 컴파일러에게 "믿어줘, 이것은 존재해"라고 말하는 것으로 생각합니다.
#import를 복사 붙여넣기로 생각합니다.
여러 가지 이유로 인해 가지고 있는 가져오기 수를 최소화하려고 합니다.아무런 연구 없이 가장 먼저 떠오르는 것은 컴파일 시간을 단축한다는 것입니다.
클래스에서 상속할 때 단순히 전달 선언을 사용할 수 없습니다.선언하는 클래스가 파일이 정의된 방식을 알 수 있도록 파일을 가져와야 합니다.
이것은 @class가 필요한 예시 시나리오입니다.
같은 클래스의 데이터 유형을 가진 매개 변수가 있는 헤더 파일 내에 프로토콜을 생성하려는 경우 @class를 사용할 수 있습니다.프로토콜을 별도로 선언할 수도 있습니다. 이것은 예에 불과합니다.
// DroneSearchField.h
#import <UIKit/UIKit.h>
@class DroneSearchField;
@protocol DroneSearchFieldDelegate<UITextFieldDelegate>
@optional
- (void)DroneTextFieldButtonClicked:(DroneSearchField *)textField;
@end
@interface DroneSearchField : UITextField
@end
언급URL : https://stackoverflow.com/questions/322597/class-vs-import
'it-source' 카테고리의 다른 글
Node.jsmongodb 드라이버 비동기/대기 쿼리 (0) | 2023.05.31 |
---|---|
저장하지 않고 Rails update_attributes? (0) | 2023.05.31 |
MongoDB에서 localhost만 듣는 방법 (0) | 2023.05.31 |
Xcode 4에서 아이폰 앱 이름 변경 (0) | 2023.05.31 |
.NET 4.0은 Windows XP SP2 이하와 호환됩니까? (0) | 2023.05.26 |