修改Objective-C块中的参数

时间:2016-04-04 09:06:14

标签: objective-c objective-c-blocks

我想修改存在于其体内的Objective-C块之外的各种变量。

我知道我可以在声明变量时使用__block属性直接访问和修改变量。所以这有效:

__block NSMutableString *alertMessage;

void(^appendMessage)(NSMutableString*, NSString*)= ^(NSString *append){

    if (!alertMessage)
    {
        alertMessage = [NSMutableString new];
    }

    if ([append length] > 0)
    {
        [alertMessage appendString:@"\n"];
    }

    [alertMessage appendString:append];
};

appendMessage(@"Alert part 1"); //This works fine

但是我想创建一个可以对传递的变量执行操作的块,使我能够对块外的多个变量使用操作而不直接访问它。如下所示:

__block NSMutableString *alertMessage;
__block NSMutableString *otherString;

void(^appendMessage)(NSMutableString*, NSString*)= ^(NSMutableString *string, NSString *append){

    if (!string)
    {
        string = [NSMutableString new];
    }

    if ([append length] > 0)
    {
        [string appendString:@"\n"];
    }

    [string appendString:append];
};

//The following do not work as intended
appendMessage(alertMessage, @"Alert Part 1"); 
appendMessage(otherString, @"Bleh bleh");     

我希望能够使用上面的块来修改在它之前声明的变量。

我怎样才能实现这样的操作?这甚至可能吗?

2 个答案:

答案 0 :(得分:2)

您的问题显示了对值和变量的一些混淆,可能以下内容会有所帮助。

  

修改Objective-C块中的参数

在(目标 - )C中,方法/函数/块的所有参数都由 value 传递,例如,在调用f(x)时,变量x的值传递给f,而不是变量本身。这称为按值调用

有些语言允许传递变量,称为按引用调用。使用时,参数必须是变量,函数中的参数名称实际上是提供的变量的别名。 (Objective-)C中不直接支持。

但是你可以在(Objective-)C中模仿它。它并不常用,但有一个值得注意的例外:许多方法使用它来返回NSError *值。

您稍后评论:

  

我想要实现的目标包括创建对象,这实质上就是现在的问题归结为。 “我可以在块内创建一个在外面声明的对象吗?”我在这里所有活动的帮助下收集到的答案是否定的。

你可以,这只是一个问题,你是否应该(即设计是对的?)以及最好的方法。

解决特定问题的直接方法是编写函数

NSMutableString *alertMessage;
NSMutableString *otherString;

NSMutableString *(^appendMessage)(NSMutableString *, NSString *) =
   ^(NSMutableString *string, NSString *append)
   {
      if (!string)
         string = [NSMutableString new];

      if (append.length > 0)
      {
         [string appendString:@"\n"];
         [string appendString:append];
      }

      return string;
   };

alertMessage = appendMessage(alertMessage, @"Alert Part 1");
otherString = appendMessage(otherString, @"Bleh bleh");

如果真的真的,真的)希望您可以通过传递地址来“传递变量”(使用{块内的{1}}运算符)和间接(使用&运算符)来获取/设置值:

*

虽然以上是有效代码,但对于像你这样的简单案例,一般不建议使用Objective-C中的编码实践。

  

获取变量的地址后,需要关注该变量的生命周期 - 如果在变量被销毁后尝试使用地址访问变量,程序将失败(悬空指针问题

void (^appendMessage)(NSMutableString **, NSString *) = ^(NSMutableString **stringPtr, NSString *append) { if (!stringPtr) return; // no "variable" passed NSMutableString *string = *stringPtr; // use indirection to get the value in the passed variable if (!string) string = [NSMutableString new]; if (append.length > 0) { [string appendString:@"\n"]; [string appendString:append]; } *stringPtr = string; // use indirection to set the passed variable }; appendMessage(&alertMessage, @"Alert Part 1"); // pass "variable" by passing its address appendMessage(&otherString, @"Bleh bleh"); 怎么样?

上述两个示例均未在任何地方使用__block

当块默认引用变量时,它会在创建块时捕获变量 value __block属性将此更改为捕获变量(因此可以通过块更改其值)并根据需要更改捕获变量的生存期(因此该变量至少与捕获块一样长,避免悬空指针问题。)

__block属性不适用于您的情况,因为您希望根据调用捕获不同的变量。

HTH

答案 1 :(得分:0)

编写的代码似乎将对象上的操作与对象创建混淆。

为清楚起见,您应该传入一个可变对象来操作您应该定义一个__block变量,其值将由块设置(并且您执行逻辑之后找出应该填充该值的位置。)

通过引用传递内容本质上是一种反模式的危险(一旦你尝试将代码重构为异步,会发生什么?至少在__block情况下,代码之后的代码该块将显示nil)。

即:

__block NSMutableString *foo = [sourceString mutableCopy];
doIt(@"new stuff"); // appends to `foo`
whereItShouldReallyGo = foo;