2017-10-25 2 views
2

나는 objective-c 라이브러리 프로젝트 ('MyLib')를 연구 중이다. 이 라이브러리가 'TestApp'에 포함되어 있다고 가정 해 보겠습니다. 이제 'TestApp'에는 'Xlib'라는 또 다른 라이브러리가 포함되어 있습니다. 이 Xlib에는 m1 메소드가있는 C1 클래스가 있습니다.객관적인 c에서 카테고리를 동적으로 만드는 방법은 무엇입니까?

//C1.h is part of Xlib 
@interface C1 
- (void) m1; 
@end 

이제 때마다 (M1)가 호출 은 MYLIB 코드의 조각을 실행해야합니다. 내가 MYLIB의 범주를 만들 경우 내 접근했다 :

@interface C1 (mycat) 
@end 

@implementation C1 (mycat) 
+ (void) load{ 
    //code to swizzle method in class C1 from: @selector(m1) to: @selector(mycat_m1) 
} 
- (void) mycat_m1{ 
    /* 
     insert code that I want to execute 
    */ 
    [self mycat_m1]; //calling the original m1 implementation 
} 
@end 

문제 : MYLIB는 클래스 C1이 없습니다. 따라서 존재하지 않는 클래스에서 카테고리를 만들려고 할 때 MyLib을 빌드 할 수 없습니다. 따라서 컴파일 오류가 발생합니다.

그래서, 나는 내부에 위의 코드를 포장하려 :

#if defined(__has_include) 
#if __has_include("C1.h") 
    /* above category code */ 
#endif 
#endif 

MYLIB 컴파일 지금은 잘 구축,하지만 C1.h이 MYLIB에 존재하지 때문에, mylib.framework이가없는 것 범주.

이제 두 가지 옵션이 있습니다 : 1.이 카테고리를 동적으로 생성하면 라이브러리가 앱에 포함되고 앱이 실행될 때 TestApp에 ​​Xlib이 포함되는지 여부에 따라이 카테고리가 생성됩니다 . 2.이 범주 코드가있는 파일을 컴파일 소스에서 제거한 다음 프레임 워크에서 해당 파일을 TestApp로 노출하십시오.

두 가지 옵션 중 하나를 해결할 수 없습니다. 기존 옵션에 대한 아이디어가 있습니까? 또는 새로운 옵션이 있습니까?

편집 : 질문 이후 추가 세부 사항은

+3

'swizzle'? 그리고 너가 원하는게 뭐야? 목적은 무엇입니까? – Simon

+0

앱에있을 수있는 클래스 c1에 메소드 m1이 있습니다. m1이 앱에서 호출 될 때마다 제 라이브러리는 코드를 실행해야합니다. 따라서, swizzling. downvote에 대해 설명해 주시겠습니까? 질문이 정확하게 틀이 맞지 않거나 여기에 명백한 것이 빠져 있습니까? – user2473992

+0

나는 그것을 투표하지 않았으므로, 저를 비난하지 마라. 질문을 제대로하는 방법에 대한 게시물을 확인하십시오. 여기에있는 내용을 이해하는 것이 정말 어렵습니다. – Simon

답변

3

이 코드는 범주에있을 필요가 없습니다 확실히 설명하지 않았다.

대부분의 경우 사람들은 특정 클래스에서 자신의 행동으로 함수를 "감싸려고"하려고하기 때문에 범주는 종종 혼란 스러울 때 사용됩니다. Swizzling은 종종 +load 클래스 메소드에서 수행됩니다. 카테고리의로드 클래스 메소드는 메인 클래스의 +load 메소드가 방금 호출되었음을 알기 때문에 조직적으로 배치하기에 좋은 장소입니다.

귀하의 경우에도 여전히 혼란 스러울 수 있습니다. +load 메소드를 사용하여 프레임 워크에 클래스를 구현하십시오. swizzling 코드는 평소와 같이 갈 것입니다. 이 범주에 속한 경우와 같이 대상 참조가 self 인 것으로 가정하는 대신 간단하게 클래스를 조회하면됩니다. 즉, 블로그 게시물을 참조하거나 좋아하는 기술을 사용하여 해당 참조를 012zz으로 바꾸면 그럴 가능성이 있음을 알고 있습니다. 당신이 어떤 수업을 듣고 있는지 조심하십시오.

저는 과거와 비슷한 것을해야했습니다. 제 경우에는 프레임 워크에서 AppDelegate 프로토콜을 구현 한 클래스의 인스턴스를 찾아야했습니다. 이 경우 Swizzling을 트리거 한 코드는 +load (AppDelegate 클래스가로드되지 않았으므로 AppDelgate의 클래스 인스턴스가 확실히 인스턴스화되지 않았으므로)에서 호출되지 않았습니다. 이 경우 클래스의 -init 메서드에서 코드를 호출하고 두 번 호출 할 수 없도록 보호했습니다. 그러나 앱 코드에서 클래스를 인스턴스화 할 수 있다는 보장이있어서 기술이 작동했습니다. 나는 당신의 유스 케이스를 100 % 확신하지 못한다. 시도한 코드를 게시하는 것이 좋습니다.

UPDATE : 구체적인 예 여기

내가 스위 즐링을위한 편리한 유지하는 방법입니다.

+ (void)swizzleSelector:(SEL)sel1 onClass:(Class)class1 withSelector:(SEL)sel2 fromClass:(Class)class2 
{ 
    Method method1 = class_getInstanceMethod(class1, sel1); 
    Method method2 = class_getInstanceMethod(class2, sel2); 

    // Make sure that both methods are on the target class (the one to swizzle likely already is). 
    class_addMethod(class1, 
        sel1, 
        method_getImplementation(method1), 
        method_getTypeEncoding(method1)); 
    class_addMethod(class1, // The swizzling is 'on' the first class, so it's the target here, not class2. 
        sel2, 
        method_getImplementation(method2), 
        method_getTypeEncoding(method2)); 

    // Once they are both added to the class, exchange the implementations of the methods. 
    method_exchangeImplementations(class_getInstanceMethod(class1,sel1), 
            class_getInstanceMethod(class1,sel2)); 
} 

내가 말했듯이, 당신은 어떻게 든 대상의 클래스를 조회해야하지만 당신은 당신의 교체 방법이있는 클래스에서이를 호출하고, m1:을 가정합니다 가정 것이다 당신이하려고하는 대상의 선택이다 당신은 다음과 같이 호출 할 수 있습니다 :

나는 이것이 당신이 swizzling으로 할 수있는 것을 명확히하는 데 도움이되기를 바랍니다. 1000 명 중 999 명은 아마 당신이 혼란 스러울 필요가 없을 것입니다. 유스 케이스는 사용자가해야 할 가능성이있는 것처럼 들립니다.

+0

@ user2473992 구체적인 예를 들어 업데이트했습니다. – greymouser

관련 문제