【问题标题】:iOS, using underscore vs using iVar directly [closed]iOS,使用下划线与直接使用 iVar [关闭]
【发布时间】:2013-03-26 18:10:08
【问题描述】:

这个问题被问了很多,但这个问题是为了获得你何时会使用这些方法的例子。请使用 setter 和 getter 无限循环以外的示例

例子。

.h -
@property(nonatomic, strong)NSMutableArray* mutArray
.m -
@synthesize mutArray= _mutArray;

1) 我想要:
_mutArray = [[NSMutableArray alloc] init];

self.mutArray=[[NSMutableArray alloc] init];
我为什么要每一个都做,有什么区别?!

2) 如果我想给它添加一个对象...
[_mutArray addObject:object];

[self.mutArray addobject:object];

为什么?!

非常感谢!

【问题讨论】:

    标签: iphone ios objective-c cocoa-touch ivar


    【解决方案1】:

    您应该只在initdealloc 或实现细节绝对需要的地方(例如访问器本身内部,或您实际需要内存地址的地方)处理您的 ivars。除了那些地方,你应该总是使用访问器,这意味着[self foo]而不是_foo

    self.foo 只是实际调用的语法糖,即[self foo]。重要的是要了解self.foo 是标准的ObjC 消息发送,与[self foo] 的含义完全相同。按照惯例,您应该只在引用属性时使用点语法。

    根据我的经验,在 ARC 之前,直接使用 ivars 是导致崩溃的第一大原因。在程序范围内直接分配给没有 ARC 的 ivar 时,您搞砸的可能性很快接近 100%。

    自 ARC 以来,我仍然认为您应该始终使用访问器(上面给出的例外情况除外),但原因更加微妙。其主要原因是可以在当前类、子类或通过 KVO (完全发生在您的代码之外)中自定义访问器。如果您直接访问 ivar,那么您将绕过它。例如,假设该属性是延迟创建的(这很常见)。然后,如果您在创建 ivar 之前使用它,您会得到一些细微的错误。因此,您必须记住,对于该属性,始终使用访问器。同样,您可以致电setNeedsDisplay 或发布通知等。

    如果您有一条简单的规则,即“我将始终使用访问器”,那么查看代码就很容易知道它是正确的。在少数需要绕过访问器的情况下,_ 会说“嘿,注意这里,我在做一些奇怪的事情。”

    如果您有一条规则“我将对需要它的属性使用访问器,但对于不需要它的属性则不使用”,那么查看代码并知道它是否正确几乎是不可能的。以前的开发人员使用 ivar 是因为它是必需的,还是仅仅因为他喜欢它?能不能改?很难知道。

    因此,即使在 ARC 之后,始终如一地使用访问器也是一种很好的防御性编程,我强烈推荐它。

    【讨论】:

    • 这与拉格纳的回答非常矛盾!您如何看待通过 setter 添加的额外保留?还有其他人可能正在使用代码并更改 setter/getter 导致意外结果的事实?
    • “额外”保留不是“额外”。这是您必须应用的必需保留,访问器是执行此操作的正确位置(这仅适用于 ARC 之前,但未能正确应用保留是我提到的崩溃的主要原因)。您想准确地使用访问器因为其他人可能正在处理代码,并且无法确保他们都知道并始终遵循“当您更改此 ivar 时,您还必须... " 记录自定义需求的正确方法是通过访问器。
    • 有时这会导致令人惊讶的结果(例如过于频繁地重新计算某些东西),但根据我的经验,这些副作用几乎总是比你不知道你有的事实更容易调试在设置 ivar 后调用 setNeedsDisplay。这会导致“除了不正常工作”之外的工作,这些工作非常难以调试。在您不知道会发生时运行访问器会显示在堆栈跟踪中。无法运行您不知道需要运行的访问器……这很难找到。
    • 所以只是为了澄清一下,在我的问题的 addobject 示例中,除非修改了 getter/setter,否则这两个会做同样的事情? [self.arr addobject:object];中实际调用了哪个,getter还是setter?
    • 他们会做几乎相同的事情。第二个不会调用[self mutArray],第一个不会。默认的 getter 实际上有原子包装器,这是不同的。您的评论示例可以重写[[self arr] addObject:object]。 (这正是我们在点语法之前的写法。)
    【解决方案2】:

    selfkeyword 就像this keywordJAVA 中。

    它访问当前对象,也是一个指向对象的指针。

    for more info about self read this tutorial

    _ObjeNameObjective c 中被称为iVar

    在实现中声明的实例变量被隐式隐藏(实际上是私有的)并且可见性无法更改- @public, @protected and @private 不会产生编译器错误(至少使用当前 Clang >) 但被忽略。

    例如:

    不同

    1) NSString *someString = _name;

    2) NSString * someString = self.name;

    假设您的 .m 文件中有这一行(并且没有任何覆盖方法来直接访问 _name)

    @synthesize name = _name;
    

    这意味着属性name (self.name) 在您尝试访问它时将使用变量_name。在这种情况下,self.name 等于 _name


    但是如果你有 name 的动态属性,像这样:

    -(NSString)name{
        return @"1234";
    }
    

    那就有区别了。 self.name 将始终返回 1234,但 _name 不能等于该值。

    例子:

    _name = @"555";
    NSLog(_name);
    NSLog(self.name);
    

    结果:

    2012-02-09 14:27:49.931 ExampleApp[803:207] 555
    2012-02-09 14:27:49.933 ExampleApp[803:207] 1234
    

    Above Example I Got From this Question.

    【讨论】:

    • 说 'self' 就像 'this' 让新开发者非常困惑。 this 可以隐含在 Java 上。 self 从未在 ObjC 中隐含。当前 Java 开发人员认为 _nameself.name 曾经意味着完全相同的东西时,这会导致很多混乱。它们永远不会完全相同,它们总是会生成不同的汇编代码,只是可能碰巧返回相同的结果。
    • @RobNapier +1。我从 Java 背景来到 ObjC,并且还与 thisself 进行了比较,虽然相关,但它们是另一回事。
    【解决方案3】:

    _mutArray 是 iVar,self.mutArray 通过 @synthesize 属性时为您创建的 getter 和 setter 访问属性。您可以将这些 getter 和 setter 覆盖为应有的自定义内容。在您的示例中,您的属性设置为强,这会为您的属性添加保留。所以 self.mutarray = [[NSMutableArray alloc] init];会做这样的事情(除非你覆盖属性的设置器):

    -(void)setMutarray:(NSMutableArray*)_mutArray{
        if(_mutArray != mutArray){
            [mutArray release];
            mutArray = nil;
            mutArray = [_mutArray retain];
        }
    }
    

    要将对象添加到数组中,您可能只想访问 iVar,而不是属性,除非您在 getter 中进行自定义操作。例如,你的吸气剂可能看起来像这样:

    -(NSMutableArray*)mutArray{
        if(!mutArray){
            self.mutArray = [[[NSMutableArray alloc] init] autorelease];
        }
        return mutArray;
    }
    

    通过这种方式,您可以确保始终有一个真实的数组来添加对象。如果是这种情况,您会想要使用 [self.mutArray addObject:object];

    因此,除非您想在 getter 或 setter 中进行自定义操作,否则您只想访问 iVar。

    【讨论】:

    • 除非我自定义,否则为什么我不想通过 setter 和 getter?
    • 您不想通过设置器,因为它会添加保留。此外,如果其他人正在使用代码,他们可能会在 getter 或 setter 中做一些您没有考虑到的事情。
    • 我不是专家,但我不同意。在非 ARC 环境中,您需要保留 - 这不是额外的。在 ARC 中,这无关紧要。要考虑的另一件事:如果您不使用访问器,则必须始终检查您的 iVar 在使用之前是否已实例化(如果不是,则为 alloc/init)。甚至不涉及 KVO 的东西,这为始终使用 setter/getter 提供了一个强有力的案例。
    猜你喜欢
    • 2012-10-17
    • 2016-05-16
    • 1970-01-01
    • 1970-01-01
    • 2010-09-12
    • 2013-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多