2012-01-06 3 views
4

가 나는 목표 - C 응용 프로그램을 개발하고, 그리고, 다음과 같은 것을 내가하고 싶은 것입니다 :개체에서 스레드로부터 안전한 모든 메시지를 어떻게 만들 수 있습니까?

+-----------------+    +---------------+ 
| Some Object | <---------- | Synchronize | 
|(Not Thread Safe)|    |  Proxy  | 
+-----------------+   /+---------------+ 
          /
          /Intercepts [someobject getCount] 
          / @synchronize (someObject) 
         /    
    [someObject getCount]/
       +----------------------+ 
       | Some Calling Object | 
       +----------------------+ 

내가 요구 한 것은, 내가 목표 - C에서 객체를 만드는 방법, 그 메시지가 다른 객체로 보내지기 전에 코드를 수행하기 위해 다른 객체로 전송 된 메시지를 가로 챕니다. (

  • 개체를 다시 쓰기 (I 클래스의 특정 인스턴스에 대한 일 만에이 필요)

    • 카테고리 나는 소스에 액세스 할 수 없습니다 : 내가 생각

      어떤 것들은 작동하지 않습니다 객체) 다시 한 번

    • 방법 스위 즐링 (당신이 경우 당신이 교류하려고하는 행동을해야 정확히 알고있는 경우에만 클래스의 특정 인스턴스)
  • +0

    그래서 'Some Object'또는 'Some Calling Object'도 제어 할 수 없습니까? – barley

    +0

    @Barley, 맞습니다. 당신이 iOS 기반 라이브러리에 그다지 액세스 할 수 없다는 것은 부끄러운 일입니다. –

    +0

    일반적으로 이런 종류의 "모든 스레드는 언제든지 모든 메서드를 호출 할 수 있습니다"동시성 패턴은 병적으로 나쁜 성능을 초래합니다. – bbum

    답변

    2

    그래서 나는 총알에 맞고 내 자신의 프록시 클래스를 만들기로 결정했습니다. 서브 클래 싱하려면 'forwardInvocation :'메시지를 재정의하고 [super forwardInvocation:]을 호출하기 전에 필요한 코드를 호출하면됩니다. 제발 Nardnvocation Vardic 방법으로 작동하지 않습니다 Vardic 방법으로 작동하지 않습니다 제발.

    #import <Foundation/Foundation.h> 
    #import <objc/runtime.h> 
    #import <objc/objc.h> 
    #import <objc/message.h> 
    
    @interface RJProxy : NSObject { 
        @private 
        NSObject *target; 
    } 
    
    @property(readwrite, retain) NSObject *target; 
    
    -(NSObject *) getTarget; 
    
    @end 
    
    @implementation RJProxy 
    
    @synthesize target; 
    
    -(NSMethodSignature *) methodSignatureForSelector:(SEL)aSelector 
    { 
        if (objc_getAssociatedObject(self, "isProxy")) 
        { 
         IMP NSObjectImp = [NSObject instanceMethodForSelector:@selector(methodSignatureForSelector:)]; 
    
         NSMethodSignature *methodSignature = (NSMethodSignature *) NSObjectImp(self, @selector(methodSignatureForSelector:), aSelector); 
    
         if (methodSignature) 
          return methodSignature; 
    
         return [target methodSignatureForSelector:aSelector]; 
        } 
        else 
        { 
         Class subClass = self->isa; 
         @try { 
          self->isa = objc_getAssociatedObject(self, "realSuperclass"); 
          return [super methodSignatureForSelector:aSelector]; 
         } 
         @finally { 
          self->isa = subClass; 
         } 
        } 
    } 
    
    -(void) forwardInvocation:(NSInvocation *)anInvocation 
    { 
        if (objc_getAssociatedObject(self, "isProxy")) 
        { 
         Class subClass = target->isa; 
         target->isa = objc_getAssociatedObject(self, "realSuperclass"); 
         [anInvocation invokeWithTarget:target]; 
         target->isa = subClass; 
        } 
        else 
        { 
         Class realSuperclass = objc_getAssociatedObject(self, "realSuperclass"); 
         Class subclass = self->isa; 
    
         self->isa = realSuperclass; 
    
         if ([self respondsToSelector:[anInvocation selector]]) 
         { 
          [anInvocation invokeWithTarget:self]; 
         } 
         else 
         { 
          [self doesNotRecognizeSelector:[anInvocation selector]]; 
         } 
    
         self->isa = subclass; 
        } 
    } 
    
    -(NSObject *) getTarget 
    { 
        if (objc_getAssociatedObject(self, "isProxy")) 
        { 
         return target; 
        } 
    
        return self; 
    } 
    
    @end 
    
    BOOL object_setProxy(NSObject *object, RJProxy *proxy); 
    BOOL object_setProxy(NSObject *object, RJProxy *proxy) 
    { 
        proxy.target = object; 
    
        Class objectClass = object_getClass(object); 
    
        Class objectSub = objc_allocateClassPair(objectClass, [[NSString stringWithFormat:@"%s_sub%i", class_getName(objectClass), objc_getAssociatedObject(objectClass, "subclassTimes")] UTF8String], 0); 
        objc_setAssociatedObject(objectClass, "subclassTimes", (id) ((int) objc_getAssociatedObject(objectClass, "subclassTimes") + 1), OBJC_ASSOCIATION_ASSIGN); 
        objc_registerClassPair(objectSub); 
    
        Class proxyClass = object_getClass(proxy); 
    
        Class proxySub = objc_allocateClassPair(proxyClass, [[NSString stringWithFormat:@"%s_sub%i", class_getName(proxyClass), objc_getAssociatedObject(proxyClass, "subclassTimes")] UTF8String], 0); 
        objc_setAssociatedObject(proxyClass, "subclassTimes", (id) ((int) objc_getAssociatedObject(proxyClass, "subclassTimes") + 1), OBJC_ASSOCIATION_ASSIGN); 
        objc_registerClassPair(proxySub); 
    
        object_setClass(object, proxySub); 
        object_setClass(proxy, proxySub); 
    
        objc_setAssociatedObject(object, "isProxy", (id) NO, OBJC_ASSOCIATION_ASSIGN); 
        objc_setAssociatedObject(proxy, "isProxy", (id) YES, OBJC_ASSOCIATION_ASSIGN); 
    
        objc_setAssociatedObject(object, "realSuperclass", objectClass, OBJC_ASSOCIATION_ASSIGN); 
        objc_setAssociatedObject(proxy, "realSuperclass", proxyClass, OBJC_ASSOCIATION_ASSIGN); 
    
        return NO; 
    } 
    
    @interface SynchronizeProxy : RJProxy 
    
    @end 
    
    @implementation SynchronizeProxy 
    
    -(void) forwardInvocation:(NSInvocation *)anInvocation { 
        @synchronized ([self getTarget]) 
        { 
         [super forwardInvocation:anInvocation]; 
        } 
    } 
    
    @end 
    
    int main (int argc, const char * argv[]) 
    { 
        @autoreleasepool { 
         NSArray *arrayToSynchronize = [NSArray arrayWithObjects:@"This, is, a, test!", nil]; 
         SynchronizeProxy *myProxy = [SynchronizeProxy new]; 
    
         object_setProxy(arrayToSynchronize, myProxy); 
    
         // now all calls will be synchronized! 
         NSLog(@"Array at address 0x%X with count of %lu, and Objects %@ ", (unsigned) arrayToSynchronize, [arrayToSynchronize count], arrayToSynchronize); 
    
         [myProxy release]; 
         [arrayToSynchronize release]; 
        } 
    
        return 0; 
    } 
    
    2

    을위한 일이 필요 당신이 찾고있는 인스턴스가 아닌 경우 메소드 swizzling을 사용하여 기본 구현을 호출 할 수 있습니다. "재미있는"인스턴스를 나열하는 전역 공유 객체를 가질 수 있으며 기본 인스턴스 또는 사용자 지정 인스턴스를 호출해야하는지 여부와 상관없이이를 활용할 수 있습니다.

    +0

    흥미 롭군요 ... 지금 당장 비슷한 접근법을 시도하고 있습니다. 제가 받아들이 기 전에 어떻게 작동하는지 보겠습니다. –

    +0

    이 접근법을 시도했지만 임의의 선택자를 가진 임의의 객체이기 때문에 인수 문제가 발생했습니다 . (얼마나 많은 변수가 뇌 기능에 있는지 알 수있는 방법이 없습니다.) –

    3

    스레드로부터 안전하지 않은 개체로 메시지를 전달하는 NSProxy를 구현할 수 있습니다.

    Here is a nice writeup 및 Objective-C에서 메시지 전달 here is Apple's documentation.

    스레드 안전을 처리하기 위해 필요한 항목에 따라 달라집니다. 스레드가 아닌 안전한 개체가 특정 스레드에서 실행되어야한다면 해당 스레드에 대해 NSRunLoop을 사용하여 해당 개체에 메시지를 직렬화 할 수 있습니다.

    Here is an example NSRunLoop과 함께 NSInvocation 사용. 이 예에서 그들은 performSelector:withObject:afterDelay:을 사용하고 있지만 performSelector:onThread:withObject:waitUntilDone:과 함께 사용하면 매우 유사합니다.

    그렇지 않은 경우 프록시에 NSRecursiveLock 하나만 사용하십시오.

    관련 문제