如何使每个消息对象接收线程安全? [英] How can I make every message an object receives thread-safe?

查看:121
本文介绍了如何使每个消息对象接收线程安全?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个Objective-C应用程序,我想做的事情如下:

I am developing an Objective-C application, and what I want to do, is something like the following:

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

我要问的是,如何在objective-c中创建一个拦截发送到另一个对象的消息的对象,以便在将消息发送到该对象之前执行代码。

What I've asking is, how can I create an object in objective-c, that intercepts messages sent to another object, in order to perform code before the message is sent to that object.

我认为有些事情是行不通的:

Some things that I think will not work:


  • 类别(我只需要这个发生在类的某些实例上)

  • 重写对象(我无权访问对象的源)

  • 方法调整(再次,这只需要发生在类的某些实例上)

推荐答案

所以,我咬紧牙关,决定自己做代理课程。要子类化,只需覆盖'forwardInvocation:'消息,然后在调用 [super forwardInvocation:] 之前调用所需的任何代码。请注意,这不适用于vardic方法,因为NSInvocation不适用于vardic方法。

So, I bit the bullet, and decided to make my own proxy class. To subclass, you simply override the 'forwardInvocation:' message, and you call any code you need there, before calling [super forwardInvocation:]. Please not this will NOT work with vardic methods, as NSInvocation doesn't work with vardic methods.

#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;
}

这篇关于如何使每个消息对象接收线程安全?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆