我想修改存在于其体内的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");
我希望能够使用上面的块来修改在它之前声明的变量。
我怎样才能实现这样的操作?这甚至可能吗?
答案 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;