【问题标题】:Passing arguments by value or by reference in objective C在目标 C 中按值或按引用传递参数
【发布时间】:2011-02-22 23:11:00
【问题描述】:

我对目标 c 有点陌生,我试图通过引用传递一个参数,但表现得好像它是一个值。你知道为什么这不起作用吗?

这是函数:

- (void) checkRedColorText:(UILabel *)labelToChange {
    NSComparisonResult startLaterThanEnd = [startDate compare:endDate];
    if (startLaterThanEnd == NSOrderedDescending){
        labelToChange.textColor = [UIColor redColor];
    }
    else{
        labelToChange.textColor = [UIColor blackColor];
    }

}

这就是电话:

UILabel *startHourLabel; // This is properly initialized in other part of the code
[self checkRedColorText:startHourLabel];

感谢您的帮助

【问题讨论】:

  • “表现得像一个价值”是什么意思?

标签: objective-c pass-by-reference


【解决方案1】:

Objective-C 支持按值传递参数。这里的问题可能已经解决了(因为这个问题已经有一年多了)但是我需要澄清一些关于论点和 Objective-C 的事情。

Objective-C 是 C 的严格超集,这意味着 C 所做的一切,Obj-C 也一样。

通过快速浏览维基百科,您可以seeFunction parameters are always passed by value

Objective-C 也不例外。这里发生的情况是,每当我们将对象传递给函数(在本例中为 UILabel *)时,我们将值 contained 传递到指针的地址。

无论你做什么,它永远是你所传递的东西的价值。如果你想传递 reference 的值,你必须传递一个 **object(就像传递 NSError 时经常看到的那样)。

这与标量相同,它们是按值传递的,因此您可以修改您在方法中收到的变量的值,而这不会改变您传递给函数的原始变量的值。

为了便于理解,举个例子:

- (void)parentFunction {
    int i = 0;
    [self modifyValueOfPassedArgument:i];
    //i == 0 still!
}

- (void)modifyValueOfPassedArgument:(NSInteger)j {
    //j == 0! but j is a copied variable. It is _NOT_ i
    j = 23;
    //j now == 23, but this hasn't changed the value of i.
}

如果您希望能够修改 i,则必须通过执行以下操作来传递 reference 的值:

- (void)parentFunction {
    int i = 0; //Stack allocated. Kept it that way for sake of simplicity
    [self modifyValueOfPassedReference:&i];
    //i == 23!
}

- (void)modifyValueOfPassedReference:(NSInteger *)j {
    //j == 0, and this points to i! We can modify i from here.
    *j = 23;
    //j now == 23, and i also == 23!
}

【讨论】:

  • 从技术上讲,是的,您只能按值传递原语。然而,这完全是一种误导,因为虽然指向对象的指针是按值传递的,但该指针指向的是同一个对象。由于没有其他方法可以传递(或处理)对象,因此 对象 总是通过引用传递。他们表现得好像不是的唯一一次是如果 OP 说 labelToChange = nil;或类似的东西,但这里的每个人都知道这是行不通的,也没有讨论。
  • 这太具有误导性了......对象是在objective-c中通过引用传递的。为了给它增加更多的乐趣,对象提出了问题并回答了按值传递的int的解释。如果这还不够有趣,你有 60 多票支持“Objective-C 仅支持按值传递参数”。
  • 这不是误导。这是 100% 正确的。 Objective-C 中只能按值传递。 句号。故事结局。对象不是通过引用传递的。传递的是指向对象的指针,并且该指针是按值传递的。结束。这些术语的含义与您认为它们应该表示的任何含义无关。
  • @Wayne 是对的。通过引用传递,调用者和被调用者使用相同的变量,而不是对对象的引用。这是一个很好的概述stackoverflow.com/questions/373419/…
【解决方案2】:

Objective-C 和 Java 一样,只有值传递。像 Java 一样,对象总是通过指针访问。 “对象”永远不是直接的值,因此您永远不会分配或传递对象。您正在按值传递对象指针。但这似乎不是问题——您正在尝试修改指针指向的对象,这是完全允许的,并且与按值传递与按引用传递无关。我认为您的代码没有任何问题。

【讨论】:

  • 但我认为,当您操作参数传递的可变对象时,情况会有所不同。 :) 原始类型(如整数、浮点数、双精度)与对象的行为方式完全不同。
  • @Neal.Marlin:传递可变对象和不可变对象在语义上没有区别。该语言没有对象“可变性”的概念。不可变对象只是碰巧没有任何改变其内部状态的方法。
  • 是的,语义上没有什么不同。但是由于方法参数原始类型是隐式复制的,所以对象不是。因为我们使用指针来保存对象。当然,C 中不支持引用。感谢您的解释。
【解决方案3】:

在objective-c 中,无法通过值传递对象(除非您明确复制它,但那是另一回事了)。戳一下你的代码——你确定 checkRedColorText: 被调用了吗? [startDate compare:endDate] 怎么样,它是否不等于 NSOrderedDescending? labelToChange 是 nil 吗?

【讨论】:

  • 在该方法中,NSOrderedDescending 有时如我所料是正确的。标签不是零。实际上,如果我将 labelToChange 连接到 startHourLabel 它可以工作......在我看来,如果我将标签作为值而不是作为参考传递:S ..我不明白..感谢您的帮助!
  • “有线 labelToChange 到 startHourLabel”是什么意思?除了将方法参数作为参数传递之外,您不能将方法参数连接到任何东西。
  • 我的意思是不使用 labelToChange 并直接使用 startHourLabel 变量(仅用于调试目的)。 startHourLabel 是全局的,可以在方法中访问。但我想对视图中的其他标签使用相同的方法。这就是我添加 labelToChange 参数的原因。谢谢!
  • 啊!全局变量 == 坏。重构代码,然后回到这个。基本上,我坚持我之前所说的;在objective-c中不可能通过值传递对象;因此这不是问题。更有可能与您使用全局变量有关。
  • 实际上,我刚刚回去阅读了这个问题,我认为@kubi 可能部分正确——'UILabel *startHourLabel;' 行是否正确实际上存在于与 checkRedColorText: 调用相同的方法中?如果是这样,并且它是一个全局变量,那么您将在局部范围内重新声明该变量,基本上这意味着它忽略了以前的定义。如果是这样,它就不会指向真正的标签。如果变量在与调用方法相同的文件中全局声明,只需省略重新声明它的行。如果不是,则将其替换为 'extern UILabel *startHourLabel;'
【解决方案4】:

你有没有在这行之间编辑掉代码

UILabel *startHourLabel;

这条线呢?

[self checkRedColorText:startHourLabel];

如果不是,问题是您要重新声明 startHourLabel 变量,因此您将丢失以前存在的任何类型的初始化。你应该在这里得到一个编译器错误。

【讨论】:

  • 这大概是为了说明的目的,因为如果没有别的,如果您对未初始化的局部变量执行任何操作,就会(可能)出现 EXE_BAD_ACCESS。
  • 您好,谢谢。不 startHourLabel 不存在,初始化是代码的其他部分。我在接口中声明了它,并为它创建了一个构造函数。我那里没有错误...
【解决方案5】:

以下是为什么这不起作用的可能性:

  1. 您传递给 checkRedColorText 的标签不是您认为的那样。
  2. 比较结果总是以相同的方式得出。
  3. ...实际上,没有3。

您声称您在其他地方初始化了 startHourLabel,但是,如果它是来自 nib 文件的标签,则根本不应该初始化它。它应该被声明为 IBOutlet 并使用接口生成器连接到 nib 中的标签。

如果它不是笔尖中的标签,即您故意以编程方式创建它,则需要检查您初始化的标签的地址并检查传递给 checkRedColorText 的标签的地址。 NSLog 初始化时的地址和 checkRedColorText 或使用调试器检查它。

【讨论】:

    猜你喜欢
    • 2023-03-04
    • 2012-10-28
    • 2012-01-16
    • 2012-10-14
    • 2014-07-11
    • 1970-01-01
    • 2023-03-02
    • 2011-01-08
    • 2011-05-08
    相关资源
    最近更新 更多