Objective-C 네임스페이스 충돌을 해결하는 가장 좋은 방법은 무엇입니까?
목표-C에는 네임스페이스가 없습니다. C와 매우 유사하며 모든 것이 하나의 글로벌 네임스페이스 내에 있습니다.IBM에서 근무하는 경우 "IBM"으로 접두사를 붙일 수 있고 Microsoft에서 근무하는 경우 "MS" 등을 사용할 수 있습니다.때때로 이니셜은 프로젝트를 참조합니다. 예를 들어, 아디움은 클래스에 "AI"를 붙입니다(그 뒤에는 이니셜을 사용할 수 있는 회사가 없기 때문입니다).Apple은 NS로 클래스를 접두사로 지정하고 이 접두사는 Apple 전용이라고 말합니다.
지금까지는 좋습니다.그러나 앞에 있는 클래스 이름에 2~4개의 문자를 추가하는 것은 매우 제한적인 네임스페이스입니다.예를 들어 MS 또는 AI는 완전히 다른 의미를 가질 수 있으며(예를 들어 AI는 인공지능일 수 있음), 일부 다른 개발자는 이를 사용하여 동일한 이름의 클래스를 만들기로 결정할 수 있습니다.쾅, 네임스페이스 충돌.
자, 만약 이것이 여러분 자신의 클래스와 여러분이 사용하고 있는 외부 프레임워크 사이의 충돌이라면, 여러분은 쉽게 여러분의 클래스의 이름을 바꿀 수 있습니다. 큰 문제가 되지 않습니다.하지만 두 개의 외부 프레임워크를 사용한다면 어떨까요? 소스가 없는 것과 바꿀 수 없는 것입니다.응용프로그램이 두 개 모두와 연결되어 이름 충돌이 발생합니다.이것들을 어떻게 해결하시겠습니까?두 클래스를 모두 사용할 수 있는 가장 좋은 방법은 무엇입니까?
C에서 라이브러리에 직접 연결하지 않고 대신 dlopen()을 사용하여 런타임에 라이브러리를 로드한 다음 dlsym()을 사용하여 찾고 있는 기호를 찾아 원하는 전역 기호에 할당한 다음 이 전역 기호를 통해 액세스할 수 있습니다.예를 들어 일부 C 라이브러리에 open()이라는 함수가 있기 때문에 충돌이 있는 경우 myOpen()이라는 변수를 정의하고 라이브러리의 open() 함수를 가리키도록 할 수 있으므로 시스템 open()을 사용하려면 open()을 사용하고 다른 하나를 사용하려면 myOpen 식별자를 통해 액세스합니다.
Objective-C에서 유사한 것이 가능하며 그렇지 않다면 네임스페이스 충돌을 해결할 수 있는 영리하고 까다로운 다른 솔루션이 있습니까?아이디어 있어요?
업데이트:
이 점을 명확히 하기 위해 네임스페이스 충돌을 사전에 방지하는 방법이나 더 나은 네임스페이스를 만드는 방법을 제안하는 답변은 환영할 수 있지만, 제 문제가 해결되지 않기 때문에 이 답변을 답변으로 받아들이지는 않겠습니다.저는 두 개의 도서관이 있는데 그들의 학급 이름이 충돌합니다.저는 그것들을 바꿀 수 없습니다. 저는 그것들의 출처를 가지고 있지 않습니다.충돌은 이미 발생했고 어떻게 미리 피할 수 있었는지에 대한 팁은 더 이상 도움이 되지 않을 것입니다.이러한 프레임워크의 개발자에게 전달할 수 있으며 향후 더 나은 네임스페이스를 선택할 수 있기를 바랍니다. 하지만 당분간은 단일 애플리케이션 내에서 프레임워크를 사용할 수 있는 솔루션을 찾고 있습니다.이것을 가능하게 하는 해결책이 있습니까?
고유한 접두사로 클래스에 접두사를 붙이는 것이 기본적으로 유일한 옵션이지만, 이를 덜 부담스럽고 추하게 만드는 몇 가지 방법이 있습니다.여기서는 옵션에 대한 긴 토론이 있습니다.내가 가장 좋아하는 것은@compatibility_alias
Objective-C 컴파일러 지침(여기에 설명됨).사용할 수 있습니다.@compatibility_alias
FQDN 또는 일부 접두사를 사용하여 클래스 이름을 지정할 수 있도록 클래스 이름을 "변경"합니다.
@interface COM_WHATEVER_ClassName : NSObject
@end
@compatibility_alias ClassName COM_WHATEVER_ClassName
// now ClassName is an alias for COM_WHATEVER_ClassName
@implementation ClassName //OK
//blah
@end
ClassName *myClass; //OK
전체 전략의 일부로, 모든 클래스에 FQDN과 같은 고유한 접두사를 사용하여 접두사를 붙인 다음 모든 클래스를 포함하는 헤더를 만들 수 있습니다.@compatibility_alias
(해당 헤더를 자동으로 생성할 수 있다고 생각합니다.)
이러한 접두사의 단점은 실제 클래스 이름(예:COM_WHATEVER_ClassName
위)는 컴파일러 외에 문자열의 클래스 이름이 필요한 모든 항목입니다.특히.@compatibility_alias
컴파일러 지시어이며 런타임 함수가 아닙니다.NSClassFromString(ClassName)
실패할 것입니다(반환).nil
를 사용해야 합니다.NSClassFromString(COM_WHATERVER_ClassName)
사용할 수 있습니다.ibtool
빌드 단계를 통해 인터페이스 빌더 닙/xib에서 클래스 이름을 수정하여 전체 COM_WHATE_...를 작성할 필요가 없습니다.인터페이스 작성기에서.
마지막 주의 사항: 이것은 컴파일러 지시사항이기 때문에(그리고 그 부분에서는 잘 알려지지 않음) 컴파일러 간에 이동할 수 없습니다.특히 LLVM-GCC(GCC 프론트엔드를 사용하는 LLVM)와 연동되어야 하는데 LLVM 프로젝트의 Clang 프론트엔드와 연동되는지 모르겠습니다.
두 프레임워크의 클래스를 동시에 사용할 필요가 없고 NSBundle 언로딩(OS X 10.4 이상, GNU 스텝 지원 없음)을 지원하는 플랫폼을 대상으로 하고 있으며 성능이 문제가 되지 않는다면 클래스를 사용해야 할 때마다 하나의 프레임워크를 로드할 수 있다고 생각합니다.그런 다음 다른 프레임워크를 사용해야 할 때 이를 언로드하고 다른 프레임워크를 로드합니다.
제 초기 아이디어는 NSBundle을 사용하여 프레임워크 중 하나를 로드한 다음 해당 프레임워크 내의 클래스를 복사하거나 이름을 바꾼 다음 다른 프레임워크를 로드하는 것이었습니다.이것에는 두 가지 문제가 있습니다.첫째, 클래스 이름을 바꾸거나 복사하기 위해 지정된 데이터를 복사하는 기능을 찾을 수 없었고, 이름이 바뀐 클래스를 참조하는 첫 번째 프레임워크의 다른 클래스는 이제 다른 프레임워크의 클래스를 참조합니다.
IMP가 가리키는 데이터를 복사할 수 있는 방법이 있는 경우 클래스를 복사하거나 이름을 변경할 필요가 없습니다.새 클래스를 만든 다음 ivar, 메서드, 속성 및 범주를 복사할 수 있습니다.훨씬 더 많은 일이 있지만, 그것은 가능합니다.그러나 프레임워크에서 잘못된 클래스를 참조하는 다른 클래스에 문제가 있습니다.
편집: C 런타임과 목표-C 런타임의 근본적인 차이점은 라이브러리가 로드될 때 해당 라이브러리의 함수는 참조하는 기호에 대한 포인터를 포함하는 반면 목표-C에서는 해당 기호의 이름에 대한 문자열 표현을 포함합니다.따라서 예제에서 dlsym을 사용하여 메모리에 있는 기호의 주소를 가져와 다른 기호에 첨부할 수 있습니다.원본 기호의 주소를 변경하지 않기 때문에 라이브러리의 다른 코드는 여전히 작동합니다.목표-C는 룩업 테이블을 사용하여 클래스 이름을 주소에 매핑하며, 1-1 매핑이므로 동일한 이름을 가진 두 클래스를 가질 수 없습니다.따라서 두 클래스를 모두 로드하려면 두 클래스 중 하나의 이름을 변경해야 합니다.그러나 다른 클래스가 해당 이름을 가진 클래스 중 하나에 액세스해야 할 경우 해당 클래스의 주소를 조회 테이블에 요청하고, 원래 클래스의 이름이 지정된 이름으로 변경된 클래스의 주소는 조회 테이블에서 반환하지 않습니다.
몇몇 사람들은 이미 문제를 해결하는 데 도움이 될 수 있는 까다롭고 영리한 코드를 공유했습니다.어떤 제안들은 효과가 있을지 모르지만, 모두 이상적이지 않고, 어떤 제안들은 실행하기에 완전히 고약합니다. (때때로 추악한 해킹은 피할 수 없지만, 저는 할 수 있을 때마다 그것들을 피하려고 노력합니다.)실용적인 관점에서, 여기 제 제안이 있습니다.
- 어떤 경우에도 개발자에게 두 프레임워크 모두 충돌에 대해 알리고, 이를 피하거나 처리하지 못하는 것이 실제 비즈니스 문제를 야기하고 있으며, 이는 해결되지 않을 경우 비즈니스 수익 손실로 이어질 수 있습니다.클래스별로 기존 충돌을 해결하는 것이 덜 방해적인 해결책이지만, 접두사를 완전히 변경하는 것(또는 접두사가 현재 없는 경우 접두사를 사용하는 것)이 동일한 문제를 다시는 보지 않도록 하는 가장 좋은 방법임을 강조합니다.
- 이름 충돌이 상당히 작은 클래스 집합으로 제한된 경우, 특히 충돌하는 클래스 중 하나가 코드에서 직접 또는 간접적으로 사용되지 않는 경우 해당 클래스만 사용할 수 있는지 확인합니다.이 경우 공급업체가 충돌하는 클래스를 포함하지 않는 프레임워크의 사용자 지정 버전을 제공할지 여부를 확인합니다.그렇지 않은 경우, 이러한 유연성으로 인해 프레임워크 사용으로 인한 ROI가 감소한다는 사실을 솔직하게 설명하십시오.이성적으로 밀어붙이는 것에 대해 기분 나쁘게 생각하지 마세요. 고객은 항상 옳습니다. ;-)
- 하나의 프레임워크가 더 "사용할 수 없는" 경우 타사 또는 홈브루의 다른 프레임워크(또는 코드 조합)로 대체하는 것을 고려할 수 있습니다.(후자는 바람직하지 않은 최악의 경우입니다. 개발과 유지보수 모두에 추가적인 비즈니스 비용이 발생할 것이 분명하기 때문입니다.)그렇다면 벤더에 프레임워크를 사용하지 않기로 결정한 이유를 정확히 알려주십시오.
- 두 프레임워크 모두 애플리케이션에 동일하게 필수적인 것으로 간주되는 경우, Louis Gerbarg가 제안한 것처럼 DO를 통해 의사소통하면서 하나 이상의 별도 프로세스에 프레임워크 중 하나를 사용할 수 있는 방법을 모색합니다.통신 정도에 따라 예상보다 나쁘지 않을 수 있습니다.일부 프로그램(QuickTime 포함)에서는 Leopard의 안전 벨트 샌드박스 프로필을 사용하여 보다 세밀한 보안을 제공하므로 코드의 특정 하위 집합만 중요하거나 중요한 작업을 수행할 수 있습니다.성능은 트레이드오프가 될 수 있지만, 유일한 옵션일 수도 있습니다.
라이센스 비용, 약관 및 기간이 이러한 사항에 대한 즉각적인 조치를 방해할 수 있다고 생각합니다.가능한 한 빨리 분쟁을 해결할 수 있기를 바랍니다.행운을 빕니다.
이것은 전체적인 것이지만 클래스 중 하나를 하위 프로그램 주소와 RPC에만 유지하기 위해 분산 개체를 사용할 수 있습니다.만약 당신이 많은 것들을 앞뒤로 주고 받는다면 그것은 엉망이 될 것입니다. 그리고 두 클래스가 모두 뷰를 직접 조작하는 등의 경우에는 불가능할 수도 있습니다.
다른 잠재적인 해결책들이 있지만, 그 중 많은 것들은 정확한 상황에 달려 있습니다.특히 최신 또는 레거시 런타임, fat 아키텍처 또는 단일 아키텍처, 32비트 또는 64비트 중 어느 쪽을 사용하고 있는지, 어떤 OS 릴리스를 대상으로 하는지, 동적으로 링크하고 있는지, 정적으로 링크하고 있는지, 아니면 선택할 수 있는지, 그리고 새로운 소프트웨어 업데이트를 위해 유지보수가 필요한 작업을 수행하는 것이 잠재적으로 괜찮습니까?
만약 당신이 정말 절박하다면, 당신이 할 수 있는 일은 다음과 같습니다.
- 라이브러리 중 하나에 직접 연결 안 함
- 로드 시 이름을 변경하는 objc 런타임 루틴의 대체 버전을 구현합니다(objc4 프로젝트를 확인하십시오. 정확히 무엇을 해야 하는지는 위에서 질문한 여러 가지 질문에 따라 다르지만 답변이 무엇이든 가능해야 합니다).
- mach_override와 같은 것을 사용하여 새로운 구현을 주입합니다.
- 일반 메서드를 사용하여 새 라이브러리를 로드합니다. 새 라이브러리는 패치된 링커 루틴을 통과하고 클래스 이름을 변경합니다.
위의 내용은 상당히 노동 집약적일 것이며, 여러 아치와 다른 런타임 버전에 대해 구현해야 하는 경우 매우 불쾌할 수 있지만, 확실히 작동할 수 있습니다.
런타임 함수(/usr/include/objc/runtime) 사용을 고려해 보셨습니까?충돌하는 클래스 중 하나를 비충돌 클래스로 복제한 다음 충돌하는 클래스 프레임워크를 로드하는 것?(이를 위해서는 충돌하는 프레임워크를 서로 다른 시간에 로드해야 합니다.)
클래스 ivar, 메서드(이름 및 구현 주소 포함) 및 이름을 런타임과 함께 검사하고 동적으로 생성하여 동일한 ivar 레이아웃, 메서드 이름/구현 주소를 가지며 이름만 다를 수 있습니다(충돌 방지).
절박한 상황은 절박한 대책을 요구합니다.라이브러리 중 하나의 개체 코드(또는 라이브러리 파일)를 해킹하여 충돌 기호를 길이는 같지만 철자가 다른 대체 이름(단, 권장 사항, 이름 길이는 같음)으로 변경하는 것을 고려해 본 적이 있습니까?본질적으로 고약한.
코드가 이름은 같지만 구현이 다른 두 함수를 직접 호출하는 것인지, 충돌이 간접적인 것인지 명확하지 않습니다.그러나 이름을 바꿀 수 있는 외부적인 가능성이 있습니다.또한 기호가 테이블에서 정렬된 순서로 정렬된 경우 이름을 변경하면 순서가 바뀌지 않도록 철자의 차이를 최소화하는 것도 좋은 방법일 수 있습니다.이진 검색과 같은 경우 검색하는 배열이 예상대로 정렬되지 않으면 문제가 발생합니다.
@compatibility_alias
클래스 네임스페이스 충돌을 해결할 수 있습니다.
@compatibility_alias NewAliasClass OriginalClass;
그러나 이렇게 해도 열거형, typeef 또는 프로토콜 네임스페이스 충돌은 해결되지 않습니다.게다가, 그것은 잘 작동하지 않습니다.@class
원래 클래스의 순행 데클대부분의 프레임워크는 typedef와 같은 클래스가 아닌 것들과 함께 제공되기 때문에 compatibility_alias만으로는 네임스페이스 문제를 해결할 수 없습니다.
저는 당신과 비슷한 문제를 살펴보았지만, 소스에 접근할 수 있었고 프레임워크를 구축하고 있었습니다.제가 찾은 최고의 해결책은@compatibility_alias
enums/suffefs/suffefs/suffets/ 등을 지원하기 위해 #filename으로 조건부로다른 충돌 프레임워크에서 항목을 확장할 위험을 최소화하기 위해 문제의 헤더에 대한 컴파일 유닛에서 조건부로 이 작업을 수행할 수 있습니다.
두 시스템의 헤더 파일을 동일한 번역 단위(소스 파일)에서 참조할 수 없다는 것이 문제인 것 같습니다.라이브러리 주변에 목적 래퍼를 만들고(프로세스에서 더 유용하게) #만 래퍼 클래스 구현에 각 라이브러리의 헤더를 포함하면 이름 충돌이 효과적으로 분리됩니다.
저는 목표-c(이제 막 시작)에서 이것에 대한 충분한 경험이 없지만, 저는 그것이 제가 C에서 할 일이라고 믿습니다.
파일에 접두사를 붙이는 것이 제가 아는 가장 간단한 해결책입니다.Cocoadev에는 네임스페이스 충돌을 방지하기 위한 커뮤니티 작업인 네임스페이스 페이지가 있습니다.자유롭게 이 목록에 당신의 것을 추가하세요, 저는 그것이 그것을 위한 것이라고 믿습니다.
http://www.cocoadev.com/index.pl?ChooseYourOwnPrefix
충돌이 발생한 경우 애플리케이션에서 프레임워크 중 하나를 리팩터링할 수 있는 방법을 잘 생각해 보시기 바랍니다.충돌이 발생한다는 것은 두 사람이 현재와 유사한 작업을 수행하고 있다는 것을 의미하며, 애플리케이션을 리팩터링하는 것만으로 추가 프레임워크를 사용할 수 있습니다.이렇게 하면 네임스페이스 문제를 해결할 수 있을 뿐만 아니라 코드를 보다 강력하고 유지보수하기 쉽고 효율적으로 만들 수 있습니다.
좀 더 기술적인 해결책보다는, 제가 당신 입장이라면 이것이 제 선택이 될 것입니다.
충돌이 정적 링크 수준에서만 발생하는 경우 기호를 해결하는 데 사용할 라이브러리를 선택할 수 있습니다.
cc foo.o -ldog bar.o -lcat
한다면foo.o
그리고.bar.o
둘 다 기호를 참조합니다.rat
그리고나서libdog
해결할 것입니다.foo.o
의rat
그리고.libcat
해결할 것입니다.bar.o
의rat
.
그냥 생각해본건데..테스트되거나 검증되지 않았으며, 기준에 부합할 수 있지만, 더 간단한 프레임워크에서 사용하는 클래스의 어댑터를 작성하는 것을 고려해 본 적이 있습니까?아니면 적어도 그들의 인터페이스?
더 간단한 프레임워크(또는 가장 적게 액세스하는 인터페이스) 주위에 래퍼를 작성하는 경우 해당 래퍼를 라이브러리로 컴파일할 수 없습니다.라이브러리가 미리 컴파일되고 헤더만 배포하면 되므로 기본 프레임워크를 효과적으로 숨기고 충돌을 통해 두 번째 프레임워크와 자유롭게 결합할 수 있습니다.
물론 두 프레임워크의 클래스를 동시에 사용해야 하는 경우가 있을 수 있지만 해당 프레임워크의 추가 클래스 어댑터를 위한 공장을 제공할 수 있습니다.그 점의 이면에서, 저는 당신이 래퍼를 만드는 데 좋은 출발점을 제공하는 두 프레임워크에서 당신이 사용하고 있는 인터페이스를 추출하기 위해 약간의 리팩터링이 필요하다고 생각합니다.
랩핑된 라이브러리에서 추가 기능이 필요할 때 라이브러리를 기반으로 빌드할 수 있으며 변경 시 재컴파일하기만 하면 됩니다.
다시 말하지만, 증명된 바는 없지만 관점을 추가하고 싶은 기분이었습니다.도움이 되길 바랍니다 :)
같은 함수 이름을 가진 두 개의 프레임워크가 있는 경우 프레임워크를 동적으로 로드할 수 있습니다.우아하지는 않겠지만, 가능합니다.오브젝티브-C 수업으로 어떻게 하는지 모르겠어요.제 생각엔NSBundle
클래스에 특정 클래스를 로드하는 메서드가 있습니다.
언급URL : https://stackoverflow.com/questions/178434/what-is-the-best-way-to-solve-an-objective-c-namespace-collision
'code' 카테고리의 다른 글
MySQL View에서 결과가 없을 때 값을 반환하려면 어떻게 해야 합니까? (0) | 2023.06.07 |
---|---|
쿼리 크기 찾기 (0) | 2023.06.07 |
MVC4 번들의 {version} 와일드카드 (0) | 2023.06.02 |
문자열에서 특수 문자를 제거하는 가장 효율적인 방법 (0) | 2023.06.02 |
단일 항목을 IEnumberable로 전달 (0) | 2023.06.02 |