Objective-C에서 클래스에 대한 개인 메소드를 정의하는 가장 좋은 방법
방금 Objective-C 프로그래밍을 시작했으며 Java 배경을 가지고 Objective-C 프로그램을 작성하는 사람들이 개인 메소드를 어떻게 처리하는지 궁금합니다.
나는 몇 가지 규칙과 습관이있을 수 있음을 이해하고 Objective-C에서 개인 방법을 다루는 사람들이 사용하는 최고의 기술을 모은 것으로이 질문에 대해 생각합니다.
게시 할 때 접근 방식에 대한 인수를 포함하십시오. 왜 좋은가요? 어떤 결점 (알고 있음)이 있으며 어떻게 처리합니까?
내 결과는 지금까지.
MyClass.m 파일에 정의 된 범주 (예 : MyClass (Private)) 를 사용 하여 개인용 메서드를 그룹화 할 수 있습니다.
이 방법에는 두 가지 문제가 있습니다.
- Xcode (및 컴파일러?)는 해당 @implementation 블록에서 개인 범주의 모든 메소드를 정의하는지 확인하지 않습니다.
- MyClass.m 파일의 시작 부분에 개인 범주를 선언하는 @interface를 넣어야합니다. 그렇지 않으면 "self는"privateFoo "메시지에 응답하지 않을 수 있습니다.
첫 번째 문제는 빈 범주 [예 : MyClass ()]로 해결할 수 있습니다 .
두 번째는 나를 많이 귀찮게합니다. 파일의 끝 부분에서 개인 메서드가 구현되고 정의되는 것을보고 싶습니다. 그게 가능한지 모르겠습니다.
다른 사람들이 이미 말했듯이 Objective-C의 개인 메소드와 같은 것은 없습니다. 그러나 Objective-C 2.0 (Mac OS X Leopard, iPhone OS 2.0 이상)을 시작으로 이름이 비어있는 (예 : Class Extension@interface MyClass ()
) 범주를 만들 수 있습니다 . 클래스 확장의 고유 한 점은 메소드 구현 이 공개 메소드 와 동일해야한다는 것입니다 . 그래서 수업을 다음과 같이 구성합니다.@implementation MyClass
.h 파일에서 :
@interface MyClass {
// My Instance Variables
}
- (void)myPublicMethod;
@end
그리고 .m 파일에서 :
@interface MyClass()
- (void)myPrivateMethod;
@end
@implementation MyClass
- (void)myPublicMethod {
// Implementation goes here
}
- (void)myPrivateMethod {
// Implementation goes here
}
@end
이 접근법의 가장 큰 장점은 메소드 구현을 (때로는 임의의) 공개 / 개인 구별이 아닌 기능별로 그룹화 할 수 있다는 것입니다.
런타임에서 사용할 구현을 해결할 수있는 경우 Objective-C에는 실제로 "비공개 메소드"가 없습니다. 그러나 문서화 된 인터페이스의 일부가 아닌 메소드가 없다고 말하는 것은 아닙니다. 그 방법에 대해서는 카테고리가 괜찮다고 생각합니다. @interface
포인트 2와 같이 .m 파일의 맨 위에 놓지 않고 자체 .h 파일에 넣었습니다. 내가 따르는 컨벤션 (그리고 다른 곳에서 보았을 때, Xcode가 자동으로 지원하는 애플 컨벤션이라고 생각합니다)은 파일을 클래스와 카테고리 다음에 +로 구분하여 이름을 지정하는 것 @interface GLObject (PrivateMethods)
입니다 GLObject+PrivateMethods.h
. 헤더 파일을 제공하는 이유는 유닛 테스트 클래스에서 가져올 수 있기 때문입니다 :-).
그건 그렇고, .m 파일의 끝 부분에 메소드를 구현 / 정의하는 한 .m 파일의 맨 아래에 카테고리를 구현하여 카테고리로 수행 할 수 있습니다.
@implementation GLObject(PrivateMethods)
- (void)secretFeature;
@end
또는 클래스 확장명 ( "빈 범주"라고 함)을 사용하는 경우 해당 메소드를 마지막에 정의하십시오. Objective-C 메소드는 구현에서 임의의 순서로 정의하고 사용할 수 있으므로 파일 끝에 "비공개"메소드를 두는 것을 막을 수있는 것은 없습니다.
클래스 확장을 사용하더라도 GLObject+Extension.h
"친구"또는 "보호 된"가시성을 모방하여 필요한 경우 이러한 메소드를 사용할 수 있도록 종종 별도의 헤더 ( )를 작성합니다 .
이 답변은 원래 작성되었으므로 clang 컴파일러는 Objective-C 메서드에 대해 두 번의 패스를 시작했습니다. 즉, "비공개"메소드를 완전히 선언하지 않고 호출 사이트의 위 또는 아래에 있는지 컴파일러에서 찾을 수 있습니다.
나는 Objective-C 전문가는 아니지만 클래스 구현에서 메소드를 개인적으로 정의합니다. 물론, 그것을 호출하는 모든 메소드 전에 (위) 정의해야하지만, 최소한의 작업이 필요합니다.
@implementation
블록 에서 개인 메소드를 정의하는 것이 대부분의 목적에 이상적입니다. Clang은 @implementation
선언 순서에 관계 없이을 (를) 볼 수 있습니다 . 클래스 연속 (일명 클래스 확장) 또는 명명 된 범주에서 선언 할 필요는 없습니다.
경우에 따라 클래스 연속에서 메소드를 선언해야합니다 (예 : 클래스 연속과와 사이의 선택기를 사용하는 경우 @implementation
).
static
기능은 특히 민감하거나 속도가 중요한 개인 방법에 매우 좋습니다.
접두사 이름 지정 규칙은 실수로 개인 메소드를 대체하지 않도록 도와줍니다 (클래스 이름을 접두어 안전으로 간주합니다).
명명 된 카테고리 (예 :) @interface MONObject (PrivateStuff)
는로드시 잠재적 인 이름 충돌로 인해 특히 좋은 아이디어가 아닙니다. 친구 나 보호 된 방법에만 유용합니다 (아주 좋은 선택은 아닙니다). 불완전한 범주 구현에 대해 경고하려면 실제로 구현해야합니다.
@implementation MONObject (PrivateStuff)
...HERE...
@end
다음은 주석이 달린 치트 시트입니다.
MONObject.h
@interface MONObject : NSObject
// public declaration required for clients' visibility/use.
@property (nonatomic, assign, readwrite) bool publicBool;
// public declaration required for clients' visibility/use.
- (void)publicMethod;
@end
MONObject.m
@interface MONObject ()
@property (nonatomic, assign, readwrite) bool privateBool;
// you can use a convention where the class name prefix is reserved
// for private methods this can reduce accidental overriding:
- (void)MONObject_privateMethod;
@end
// The potentially good thing about functions is that they are truly
// inaccessible; They may not be overridden, accidentally used,
// looked up via the objc runtime, and will often be eliminated from
// backtraces. Unlike methods, they can also be inlined. If unused
// (e.g. diagnostic omitted in release) or every use is inlined,
// they may be removed from the binary:
static void PrivateMethod(MONObject * pObject) {
pObject.privateBool = true;
}
@implementation MONObject
{
bool anIvar;
}
static void AnotherPrivateMethod(MONObject * pObject) {
if (0 == pObject) {
assert(0 && "invalid parameter");
return;
}
// if declared in the @implementation scope, you *could* access the
// private ivars directly (although you should rarely do this):
pObject->anIvar = true;
}
- (void)publicMethod
{
// declared below -- but clang can see its declaration in this
// translation:
[self privateMethod];
}
// no declaration required.
- (void)privateMethod
{
}
- (void)MONObject_privateMethod
{
}
@end
분명하지 않은 또 다른 접근법 : C ++ 유형은 매우 빠르며 훨씬 높은 수준의 제어를 제공하면서 내보내고로드 된 objc 메소드의 수를 최소화합니다.
인스턴스에 대한 포인터를 사용하는 구현 아래 또는 위에 정적 함수를 정의 할 수 있습니다. 모든 인스턴스 변수에 액세스 할 수 있습니다.
//.h file
@interface MyClass : Object
{
int test;
}
- (void) someMethod: anArg;
@end
//.m file
@implementation MyClass
static void somePrivateMethod (MyClass *myClass, id anArg)
{
fprintf (stderr, "MyClass (%d) was passed %p", myClass->test, anArg);
}
- (void) someMethod: (id) anArg
{
somePrivateMethod (self, anArg);
}
@end
블록을 사용할 수 있습니까?
@implementation MyClass
id (^createTheObject)() = ^(){ return [[NSObject alloc] init];};
NSInteger (^addEm)(NSInteger, NSInteger) =
^(NSInteger a, NSInteger b)
{
return a + b;
};
//public methods, etc.
- (NSObject) thePublicOne
{
return createTheObject();
}
@end
나는 이것이 오래된 질문이라는 것을 알고 있지만,이 질문에 대한 답을 찾을 때 처음 발견 한 것 중 하나입니다. 이 솔루션이 다른 곳에서 논의 된 것을 보지 못했기 때문에이 작업에 어리석은 것이 있으면 알려주십시오.
Objective C의 모든 객체는 performSelector : 메소드 를 보유하는 NSObject 프로토콜을 따릅니다 . 또한 이전에는 공개 수준에서 노출 할 필요가없는 "도우미 또는 개인"방법을 만드는 방법을 찾고있었습니다. 오버 헤드없이 개인 메소드를 만들고 헤더 파일에서 정의하지 않아도되는 경우이 샷을 제공하십시오 ...
아래 코드와 비슷한 서명으로 메소드를 정의하십시오 ...
-(void)myHelperMethod: (id) sender{
// code here...
}
그런 다음 메소드를 참조해야 할 때 단순히 선택기로 호출하십시오 ...
[self performSelector:@selector(myHelperMethod:)];
이 코드 줄은 사용자가 만든 메소드를 호출하며 헤더 파일에 정의되지 않은 것에 대해 성가신 경고를하지 않습니다.
@interface
맨 위 의 블록 을 피하려면 항상 비공개 선언을 MyClassPrivate.h
이상적이지 않지만 구현을 방해 하지 않는 다른 파일에 넣을 수 있습니다.
MyClass.h
interface MyClass : NSObject {
@private
BOOL publicIvar_;
BOOL privateIvar_;
}
@property (nonatomic, assign) BOOL publicIvar;
//any other public methods. etc
@end
MyClassPrivate.h
@interface MyClass ()
@property (nonatomic, assign) BOOL privateIvar;
//any other private methods etc.
@end
MyClass.m
#import "MyClass.h"
#import "MyClassPrivate.h"
@implementation MyClass
@synthesize privateIvar = privateIvar_;
@synthesize publicIvar = publicIvar_;
@end
내가 여기서 보지 못한 것 하나 더-Xcode는 이름에 "_private"가있는 .h 파일을 지원합니다. MyClass 클래스가 있다고 가정 해 봅시다. MyClass.m 및 MyClass.h가 있고 이제 MyClass_private.h도 가질 수 있습니다. Xcode는이를 인식하여 Assistant Editor의 "Counterparts"목록에 포함시킵니다.
//MyClass.m
#import "MyClass.h"
#import "MyClass_private.h"
문제 # 2를 해결할 방법이 없습니다. 이것이 바로 C 컴파일러 (따라서 Objective-C 컴파일러)가 작동하는 방식입니다. XCode 편집기를 사용하는 경우 함수 팝업으로 파일 의 @interface
및 @implementation
블록을 쉽게 탐색 할 수 있습니다.
개인용 메소드가 없다는 이점이 있습니다. 숨기려는 논리를 별도의 클래스로 이동하여 위임으로 사용할 수 있습니다. 이 경우 대리자 개체를 개인으로 표시 할 수 있으며 외부에서 볼 수 없습니다. 로직을 별도의 클래스 (아마도 여러 개)로 옮기면 프로젝트를 더 잘 설계 할 수 있습니다. 클래스가 더 단순 해지고 메소드가 적절한 이름을 가진 클래스로 그룹화됩니다.
다른 사람들이 말했듯이 @implementation
블록 에서 개인 메소드를 정의하는 것은 대부분의 목적으로 괜찮습니다.
코드 구성 주제 pragma mark private
-Xcode에서 쉽게 탐색 할 수 있도록 코드를 함께 유지하고 싶습니다.
@implementation MyClass
// .. public methods
# pragma mark private
// ...
@end
'development' 카테고리의 다른 글
비동기 및 비 차단 (0) | 2020.03.01 |
---|---|
JSON에서 null을 나타내는 (0) | 2020.03.01 |
힘내 충돌 마커 (0) | 2020.03.01 |
Windows 명령 프롬프트 출력 표시 및 파일로 리디렉션 (0) | 2020.03.01 |
MVC 3에서 현재 페이지 URL을 얻는 방법 (0) | 2020.03.01 |