修改Objective-C块中的参数

修改Objective-C块中的参数,objective-c,objective-c-blocks,Objective C,Objective C Blocks,我想修改存在于Objective-C块之外的各种变量 我知道在声明变量时,我可以使用\u block属性直接访问和修改变量。所以这是可行的: __block NSMutableString *alertMessage; void(^appendMessage)(NSMutableString*, NSString*)= ^(NSString *append){ if (!alertMessage) { alertMessage = [NSMutableStri

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

我知道在声明变量时,我可以使用
\u 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");     
我希望能够使用上面的块来修改前面声明的变量


我怎样才能完成这样的手术?这可能吗?

编写的代码似乎混淆了对象操作和对象创建

为了清楚起见,您应该传入一个要操作的可变对象,或者应该定义一个
\uu块
变量,其值将由块设置(然后执行逻辑以确定该值应填充到何处)

通过引用传递某些内容本质上是危险的,甚至会成为一种反模式(当您尝试将代码重构为异步时会发生什么?至少在
\u块
的情况下,块后的代码将看到
nil

i、 e:


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

修改Objective-C块中的参数

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

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

但是,您可以在(Objective-)C中模拟它。它不常用,但有一个显著的例外:许多方法使用它来返回
NSError*

您稍后的评论:


我想要实现的包括对象创建,这基本上就是现在的问题。“我可以在块的外部创建声明的对象吗?”。我在这里所有活动的帮助下得出的答案是否定的

你可以,这只是一个问题,你是否应该(即设计是正确的吗?)和最好的方法

解决特定问题的简单方法是编写函数:

如果您真的(真的,真的)想要,您可以通过在块内传递其地址(使用
&
运算符)和间接(使用
*
运算符)来“传递变量”,以获取/设置值:

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");
虽然上述代码是有效的,但对于像您这样的简单情况,通常不建议使用Objective-C进行编码

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

\uu块呢

上述示例均未在任何地方使用
\u块

默认情况下,当块引用变量时,它将捕获创建块时的变量值。
\uu块
属性将此更改为捕获变量(因此块可以更改其值),并根据需要更改捕获变量的生存期(因此变量的生存期至少与捕获块的生存期相同,避免了悬空指针问题)

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


HTH

您可以创建一个C函数,它也可以执行同样的操作。为什么要为此目的使用块?@wolfgangchreurs块中指定的操作在特定函数中是必需的。虽然一个C函数确实可以做到这一点(或者说是一个Objective-C函数),但在一个块中声明相同的操作将有额外的好处,即隔离代码以供在函数中使用,并使其更可读。为什么不能在(块外)之前初始化参数,这是唯一导致您出现“问题”的因素@Wain我希望变量为零。是的,我可以简单地检查他们的长度之后。。。这不像我希望的那么干净。谢谢现在很明显,这无法如愿实现。出于学术目的,很高兴知道。我想你可以传递一个指向指针的指针,我以前从未尝试过块。我想实现的包括对象创建,这基本上就是现在的问题。“我可以在块的外部创建声明的对象吗?”。我在这里所有活动的帮助下得出的答案是否定的。谢谢!很好的解释。谢谢
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");
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");