Objective-C检测是否可以保留参数?

时间:2010-11-25 11:30:35

标签: objective-c arguments retain

我正在运行一个参数列表,但在这些参数中,值可以是NSInteger,Selector到NSObjects。但如果是NSObject,则需要妥善保留。我不能简单地检查该类是否与NSObject相同,或者它是否响应了retain方法,因为如果你在选择器或整数上执行它,它将简单地崩溃。那么你怎么能这样做呢?我不知道。

我甚至尝试将@try @catch放入其中,尝试保留,如果不是,它可能是一个不需要保留的对象。但它也立即崩溃了:(这里没有错误异常。


如果我只能测试某个参数是否有类,如果找到一个类,我可以检查它是否为NSObject类,如果没有找到类,则不应该保留它。我找到了:

object_getClass();

但是当你在其中传递NSInteger时它会崩溃。


查看NSInvocation类,您可以调用retainArguments方法,不幸的是,这也会使应用程序崩溃。但是在setArgument的描述中有一些奇怪的东西:

  

当参数值是对象时,将指针传递给应从中复制对象的变量(或内存)

这意味着有一些“东西”可以检测出一个参数是一个对象,但是如何?


代码(到现在为止)

- (void)addObserver:(NSObject *)observer selector:(SEL)selector arguments:(id)firstObj, ... {
    // Define signature
    NSMethodSignature *signature  = [[observer class] instanceMethodSignatureForSelector:selector];
    NSInvocation      *invocation = [NSInvocation invocationWithMethodSignature:signature];

    // Prepare invocation
    [invocation setTarget:observer];
    [invocation setSelector:selector];

    id        currentObject;
    va_list   argumentsList;
    NSInteger currentIndex = 2;

    if (firstObj) {
        va_start (argumentsList, firstObj);
        while (currentObject = va_arg(argumentsList, id)) {
            [invocation setArgument:&currentObject atIndex:currentIndex];
            currentIndex++;
        }
        va_end(argumentsList);
    }

    // The observer can easily be retained by doing [observer retain];
    // However the arguments may consist of NSIntegers etc. which really don't like
    // to be retained (logically). So I want to skip the argument that don't need
    // retaining.
}

目标

我想要完成的是以下内容:

我有一个随机方法,如:

- (void)fetchFruitApples:(NSInteger)amount inRange:(NSRange)range withString:(NSString *)aString {
    //Can I fetch fruit? 
    //If so, execute method. 
    //If not wait for a certain event to occur (without blocking the main thread) 
    //Then retry this method with the arguments passed.
    //Thats why here I want to do [MyObject addObserver:self selector:@selector(fetchFruitApples:inRange:withString:) arguments:amount, range, aString, nil];
}

5 个答案:

答案 0 :(得分:0)

如何将您的数字作为NSNumber对象传递,这样您就可以确保获得的所有内容都是一个对象,并会响应[arg retain][arg isKindOfClass:[NSNumber class]]

之类的内容

我肯定不知道这一点,但我会做出有根据的猜测,没有办法做到这一点。您可以在int和对象之间进行区分,但是要指出指向选择器的指针和指向对象的指针?值得怀疑的。

答案 1 :(得分:0)

你声明的目标让我觉得你应该探索NSOperationQueue。

“这让我接下来讨论NSOperation依赖项.NSThread目前还没有用于添加依赖项的内置机制。但是NSOperation有 - (void)addDependency:(NSOperation *)操作方法,它允许一个简单的机制(当与NSOperationQueue一起使用时)用于依赖管理。所以我们进入NSOperationQueue ......“

来自http://cocoasamurai.blogspot.com/2008/04/guide-to-threading-on-leopard.html

答案 2 :(得分:0)

您最好的选择可能只是使用格式字符串,就像使用[NSString stringWithFormat:]一样。调用者总是知道正确的类型,那么为什么不让它传递信息呢?

例如,如果您将方法签名更改为:

- (void)addObserver:(NSObject *)observer selector:(SEL)selector argumentFormat:(NSString*)format arguments:(id)firstObj, ... {

  // parse format

}

format类似于:isS并且意味着第一个参数是一个整数,第二个是字符串,第三个是选择器(即保留第二个参数但不保留另一个二)。

答案 3 :(得分:0)

可能是最简单的解决方案:

[myInvocation setRetainArguments:YES];

这将告诉调用实例保留您设置的任何对象参数。所以从你的角度来看,根本就没有工作。

如果您需要手动执行,那么您应该查看方法-[NSMethodSignature getArgumentTypeAtIndex:]。它将返回char *,其编码类型与@encode()使用的格式相同。可以这样使用:

char* type = [myMethodSignature getArgumentTypeAtIndex:3];
if (strcmp(type, @encode(id)) == 0) {
  // It is an object!
}

最后,我已经完成了您可能需要的工作,您可以轻松创建NSInvocation个实例,以使用单个语句调用任何类型的参数。在后台/主线程,延迟和操作队列上都有。

我已就该主题发表过博文,完整的源代码可从此处获取:http://blog.jayway.com/2010/03/30/performing-any-selector-on-the-main-thread/

以及更多:http://blog.jayway.com/2010/08/19/future-cocoa-operation/

答案 4 :(得分:0)

最后解决方案

经过艰难的一天,希望发现看起来不可能的事情,我终于有了解决方案,特别感谢PeyloW指出我正确的方向。阅读他的博客: http://blog.jayway.com/2010/03/30/performing-any-selector-on-the-main-thread/

关键是:

const char *type   = [signature getArgumentTypeAtIndex:index];
NSString *dataType = [[[NSString alloc] initWithCString:type] autorelease];
if ([dataType isEqualToString:@"@"]) // The argument is an object!