【问题标题】:How to create an NSInvocation object using a method that takes a pointer to an object as an argument如何使用将指向对象的指针作为参数的方法创建 NSInvocation 对象
【发布时间】:2012-04-03 03:58:11
【问题描述】:

我想使用一个方法创建一个 NSInvocation 对象,该方法将一个指向 NSError 对象的指针作为参数。一个例子就是方法 -

- (BOOL)writeToFile:(NSString *)path options:(NSDataWritingOptions)mask error:(NSError **)errorPtr

我明白我会这样设置我的调用

NSData *myData = [[NSData alloc] init];

SEL writeToFileSelector = @selector(writeToFile:options:error:);
NSMethodSignature *signature = [NSData instanceMethodSignatureForSelector:writeToFileSelector];

NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
[invocation setTarget:myData];
[invocation setSelector:writeToFileSelector];

NSString *string = [NSString stringWithFormat:@"long cat"];
NSDataWritingOptions *dataOptions;
*dataOptions = NSDataWritingFileProtectionComplete;

[invocation setArgument:&string atIndex:2];
[invocation setArgument:&dataOptions atIndex:3];

对于 writeToFile:Options:Error:最后一个参数期望接收指针而不是对象。因此,执行以下操作不起作用 -

NSError *err = nil;
[invocation setArgument:&err atIndex:4];

解决方案可能是创建指向指针的指针似乎是合乎逻辑的,但这会导致编译器警告。我不确定如何正确执行它并且不会产生内存管理问题。

【问题讨论】:

    标签: ios cocoa-touch automatic-ref-counting nserror nsinvocation


    【解决方案1】:

    您创建的参数与您传递给方法的任何其他参数一样。

    正如您所指出的,方法签名需要一个 NSError ** 作为其最后一个参数(索引 4)。所以,你需要声明一个,但有一点问题。

    NSError **errorPointer

    给你一个指向 NSError 变量的变量。但是,由于您没有告诉它指向任何变量,所以它指向 nil。因此,当您触发调用时,选择器将无法更改错误指针指向的变量。换句话说,这就像打电话给[myData writeToFile:string options:dataOptions error:NULL]

    因此,您还需要声明一个 NSError 变量,并将其地址分配为您的 errorPointer 应指向的变量:

    NSError *error;
    NSError **errorPointer = &error;
    

    现在您可以将 errorPointer 作为参数传入,如果在调用该方法时出现问题,您可以稍后检查它。查看this post on NSInvocation 以获得更多帮助(向Mark Dalrymple 致敬以指出博文)

    还有一点很重要,即应该为您创建并传递给调用的参数考虑范围。看看我问过的类似问题here

    【讨论】:

    • “但是,因为你没有告诉它指向任何变量,所以它指向 nil。”什么?不,它是未定义的
    • “现在你可以将errorPointer作为参数传递”你没有解释如何传递它。
    • #1 在 ARC 下,未赋值的局部指针变量自动设置为 nil。在 C 或非 ARC Obj-C 中,您是正确的。 #2 将errorPointer作为第四个参数传递[invocation setArgument:&errorPointer atIndex:4]
    【解决方案2】:

    edelaney05 接受的答案很棒,但我认为它需要对 ARC 稍作调整。 (我还不能添加 cmets,所以创建一个新的答案来记录我的发现)

    按原样,我得到了编译错误: "指向非 const 类型 'NSError *' 的指针,没有明确的所有权"

    我研究了这个,发现我需要:

     NSError * __autoreleasing error = nil;
     NSError * __autoreleasing *errorPointer = &error;
    

    导致我得到这个答案的参考资料:

    NSInvocation & NSError - __autoreleasing & memory crasher

    Automatic Reference Counting: Pointer to non-const type 'NSError *' with no explicit ownership

    http://developer.apple.com/library/ios/#releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html

    “__autoreleasing 用于表示通过引用 (id *) 传递并在返回时自动释放的参数。”

    【讨论】:

      【解决方案3】:

      参数类型是NSError **,您可以通过获取您希望写入错误的NSError * 的地址来获得该参数类型。要在NSInvocation 中设置参数,您需要将参数值的地址传递给setArgument:,因此您需要将NSError ** 放入一个变量中(我在这里称之为errPointer),并且将其地址(将是NSError ***)传递给setArgument:。之后您就不需要 errPointer 变量了。

      NSError *err = nil;
      NSError **errPointer = &err;
      [invocation setArgument:&errPointer atIndex:4];
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-05-18
        • 2012-07-15
        • 1970-01-01
        • 1970-01-01
        • 2023-02-09
        • 2018-02-25
        相关资源
        最近更新 更多