Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/98.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c @synthesis foo=\u foo是关于什么的?_Objective C_Ios_Automatic Properties - Fatal编程技术网

Objective c @synthesis foo=\u foo是关于什么的?

Objective c @synthesis foo=\u foo是关于什么的?,objective-c,ios,automatic-properties,Objective C,Ios,Automatic Properties,为什么要在iOS应用程序中使用下划线前缀?保持ivar(实例变量)安全是一种惯例,因此只能通过getter和setter访问它。以下是我有时这样做的原因: 如果我想在属性上执行延迟加载,我通常会在ivar下面加下划线,以便从后端服务器/保存的文件/您拥有的内容加载所需数据时所做的工作只在第一次加载。例如: - (NSMutableArray *)recentHistory; { if (_recentHistory == nil) { // Get it and set

为什么要在iOS应用程序中使用下划线前缀?

保持ivar(实例变量)安全是一种惯例,因此只能通过getter和setter访问它。

以下是我有时这样做的原因:

如果我想在属性上执行延迟加载,我通常会在ivar下面加下划线,以便从后端服务器/保存的文件/您拥有的内容加载所需数据时所做的工作只在第一次加载。例如:

- (NSMutableArray *)recentHistory;
{
   if (_recentHistory == nil)
   {
       // Get it and set it, otherwise no work is needed... hooray!
   }

   return _recentHistory;
}
因此,在这里调用属性[InstanceOffClass recentHistory](或InstanceOffClass.recentHistory)将检查ivar,查看它是否需要加载数据或只是返回已加载的数据

以这种方式声明所有属性太过分了


希望这能有所帮助。

有时候,了解幕后发生的事情有助于理解。基本上当你看到这个的时候

@property (nonatomic, retain) Foo *foo;
随着这一点的实施

@synthesize foo=_foo;
下面是语法糖,这意味着编译器基本上会为您生成此代码

Foo *foo = nil;

-(Foo *) foo {
    return _foo;
}

-(void) setFoo:(Foo *)val {
    if( _foo != val ) {
        [_foo release];
        _foo = [val retain];
    }
}
通过这种方式,当您引用公共属性时,您可以通过生成的self.foo附件点击它,如果您想引用类中的实例变量,您可以引用\u foo。在XCode 4之前,很容易将两者混淆。你可以这样做

self.foo = foo1;

foo = foo2;
这是完全合法的,可能会在几个层面上造成问题。第二行不使用访问器,因此不会保留foo2,这可能导致垃圾收集过早地提取它。更糟糕的是,第二行没有使用访问器,这将释放任何先前的值,这意味着它将导致内存泄漏


总之,这项新技术为您创建了一个getter和setter属性,并允许您指定用于封装的实例变量的名称。

只是想将我的想法添加到上述所有答案中

就我而言,我使用它主要是为了保证我的课程不会发生意外

在我的.h文件中,我只声明没有IVAR的属性。在.m文件中,我使用上面的
@synthesis
模式对用户(包括我自己)隐藏实际的ivar,以强制用户使用合成/动态访问器,而不是直接使用其他ivar。您可以在ivar名称中使用任何内容,而不仅仅是下划线。e、 g.你可以做:

@synthesize foo = _mySecretFoo;
@synthesize bar = oneUglyVarBecauseIHateMyBoss;
这样,您的上司只会看到条形图,您会发现使用条形图访问器(无论您使用点符号还是消息)更容易,也更安全

我更喜欢这种方法

@property (getter=foo, setter=setFoo, ...) _mySecretFoo;
@property (getter=bar, setter=setBar, ...) oneUglyVarBecauseIHateMyBoss;

因为这并不强制私有实现和封装,当Xcode可以为您做同样的事情时,这只是额外的键入。要记住的一点是,属性与IVAR不同!您可以拥有比IVAR更多的属性,或者反过来说。

更好的约定是不使用点语法。@synthesis(通常属性)与点语法完全正交。很好的解释。只是吹毛求疵:
if(\u-foo!=nil)[\u-foo-release]编译器没有生成测试vs nil,这将是无用的,它宁愿测试新值是否与以前的值不同。请参阅以获取示例。尝试使用
Foo*tmp=[Foo-Foo]运行代码;self.foo=tmp;self.foo=tmp看到它蓬勃发展。我在我的iPad上敲出了这个答案,我不是100%确定确切的实现,但我想真正强调一个事实,它为您处理内存管理,并帮助避免冲突。谢谢你的提醒!jv42,在您的第二条评论中,Foo*tmp=[Foo-Foo];不应编译,因为-(Foo*)Foo在类级别不可访问。现在,如果签名被更改为+(Foo*)Foo,那么[Foo Foo]将是完全合法的,然而,事实并非如此。嗯,对不起,我暗示的是一个使用标准命名约定的方法返回一个自动删除的Foo实例。此处的属性名称不符合此约定。如果我已正确阅读此项,则在
@implementation{…}
块中执行此操作时,不会显式声明IVAR。使用
@synthesis bar=one有什么好处如果你从来没有提到过
oneught
?为什么不直接做
@合成吧?这是因为如果您编写eg
bar=123.0
,您的方式会出错吗?您的意思是在@interface{}块中声明IVAR。是的,如果您使用bar=123,您将得到一个错误,但这不是您使用上述模式的原因。这种模式是一种方便的方式,它允许公开一个公共接口,同时完全隐藏您的实现,就像下面这个例子中的apple文档:
@syntheize age=numberOfYears它还允许我做:
SomeAccount*account=[someaccountdefaultaccount];self.account=账户
并在
recentHistory
方法中使用实例变量
recentHistory
self->recentHistory
,只需确保不使用属性名
self.recentHistory
[self-recentHistory]
并导致递归。不,作为惯例。这是一个惯例,你可以在苹果的代码中找到,这可能就是人们使用它的原因。拥有一个iVar和一个财产的想法有时被过度使用,但我认为这是一个值得考虑的问题。