@property在Objective-C中保留,分配,复制,非原子


214

作为Objective-C的新手,有人可以给我一个有关@property指令的保留,分配,复制以及我所缺少的其他内容的概述吗?他们在做什么,为什么我要一个又一个地使用?


1
苹果公司的这些名称是“属性”或“属性属性”

Answers:


273

MrMage链接到的文章不再有效。因此,这是我在Objective-C中(很短时间内)编码中学到的内容:

非原子与原子-默认为“原子”。始终使用“非原子”。我不知道为什么,但是我读过的书说使用“原子的”是“很少的理由”。(BTW:我读的书是BNR“ iOS编程”书。)

readwrite vs. readonly-默认为“ readwrite”。@synthesize时,将同时为您创建一个getter和setter。如果使用“只读”,则不会创建任何setter。将其用于您不想在对象实例化后更改的值。

保留vs.复制vs.分配

  • 默认为“分配”。在由@synthesize创建的设置器中,该值将简单地分配给该属性。我的理解是“分配”应用于非指针属性。
  • 当属性是指向对象的指针时,需要“保留”。@synthesize生成的设置器将保留(也称为添加保留计数)对象。完成处理后,您将需要释放该对象。
  • 当对象可变时,需要“复制”。如果您现在需要该对象的值,并且不希望该值反映该对象的其他所有者所做的任何更改,请使用此值。完成对象后,您将需要释放它,因为您保留了副本。

@Blamdarot-我是否也需要用ARC释放它
Dejell 2012年

10
@Odelya-否。如果您在使用ARC的同时发布,我相信您会收到编译器错误。
布拉达罗特2012年

52
“始终使用非原子”是个坏建议。当您使用非原子时,您应该知道自己要放弃什么。
Jesse Rusak 2013年

7
同意 特别是,很多人似乎并不知道非原子值不会被吸气剂保留并自动释放。非原子的通常是合适的,但是很少使用“货物崇拜”编程。
Catfish_Man

9
atomic劝告保留默认值与劝告一样糟糕nonatomic。两种选择都不是“正确的”选择,因此语言设计人员选择了两种解决方案中较安全的一种。实际上nonatomic,通常是更好的选择,因为它省去了极其昂贵的线程锁。唯一使用的原因atomic是,如果您的属性可能是从多个线程设置的(在这种情况下,忽略它可能导致过度释放或泄漏)。
亚当·卡普兰

295

在了解@property的属性之前,您应该知道@property的用途。

  • @property提供了一种定义类打算封装的信息的方法。如果使用@property声明对象/变量,则其他导入其类的类将可以访问该对象/变量。

  • 如果在头文件中使用@property声明对象,则必须在实现文件中使用@synthesize对其进行合成。这使对象符合KVC要求。默认情况下,编译器将为此对象综合访问器方法

  • 访问器方法是:setter和getter。

例如:.h

@interface XYZClass : NSObject
@property (nonatomic, retain) NSString *name;
@end

.m

@implementation XYZClass
@synthesize name;
@end

现在,编译器将为name合成访问器方法。

XYZClass *obj=[[XYZClass alloc]init];
NSString *name1=[obj name]; // get 'name'
[obj setName:@"liza"]; // first letter of 'name' becomes capital in setter method
  • @property的属性列表

    原子,非原子,保留,复制,只读,读写,分配,强,getter =方法,setter =方法,unsafe_unretained

  • 默认行为是atomic。如果一个对象被声明为原子对象,那么它将成为线程安全的。线程安全意味着,一次该类的特定实例的一个线程只能控制该对象。

如果线程正在执行getter方法,则其他线程无法对该对象执行setter方法。太慢了

@property NSString *name; //by default atomic`
@property (atomic)NSString *name; // explicitly declared atomic`
  • 非原子 的不是线程安全的。您可以使用nonatomic属性属性来指定合成访问器仅直接设置或返回一个值,而不能保证如果从不同线程中同时访问同一值会发生什么情况。

因此,访问非原子属性比原子属性要快。

@property (nonatomic)NSString *name;   
  • 当属性是指向对象的指针时,retain是必需的。

setter方法将增加对象的保留计数,以便它将占用自动释放池中的内存。

@property (retain)NSString *name;
  • 复制如果使用复制,则不能使用保留。使用该类的副本实例将包含其自己的副本。

即使设置了可变字符串并随后对其进行了更改,实例也会捕获设置时具有的任何值。不会合成setter和getter方法。

@property (copy) NSString *name;

现在,

NSMutableString *nameString = [NSMutableString stringWithString:@"Liza"];    
xyzObj.name = nameString;    
[nameString appendString:@"Pizza"]; 

名称将不受影响。

  • readonly如果您不想允许通过setter方法更改属性,则可以将属性声明为readonly。

编译器将生成一个getter,但不会生成setter。

@property (readonly) NSString *name;
  • readwrite是默认行为。您不需要显式指定readwrite属性。

与readonly相反。

@property (readwrite) NSString *name;
  • Assign将生成一个setter,它将值直接分配给实例变量,而不是复制或保留它。这最适合诸如NSInteger和CGFloat之类的原始类型,或不直接拥有的对象(例如委托)。

请记住,启用垃圾收集后,保留和分配基本上可以互换。

@property (assign) NSInteger year;
  • 强大是保留的替代品。

它带有ARC。

@property (nonatomic, strong) AVPlayer *player; 
  • getter = method如果要对getter方法使用其他名称,则可以通过向属性添加属性来指定自定义名称。

对于布尔属性(具有YES或NO值的属性),getter方法通常以单词“ is”开头

@property (getter=isFinished) BOOL finished;
  • setter = method如果要为setter方法使用其他名称,则可以通过向属性添加属性来指定自定义名称。

该方法应以冒号结尾。

@property(setter = boolBool:) BOOL finished;
  • unsafe_unretained Cocoa和Cocoa Touch中有一些类尚不支持弱引用,这意味着您无法声明弱属性或弱局部变量来跟踪它们。这些类包括NSTextView,NSFont和NSColorSpace等。如果需要使用对这些类之一的弱引用,则必须使用不安全的引用。

不安全引用类似于弱引用,因为它不会保持其相关对象处于活动状态,但是如果释放了目标对象,则不会将其设置为nil

@property (unsafe_unretained) NSObject *unsafeProperty;

如果需要指定多个属性,只需将它们作为逗号分隔的列表包括在内,如下所示:

@property (readonly, getter=isFinished) BOOL finished;

此外,弱表示没有引用计数引用到对象,但它完全被引用或完全未被引用。有点像“是的,有些东西引用了我”与“ 9种引用我的存在”(就是强一样)。
Alex Zavatone

6
忽略答案中关于垃圾收集的这一行,因为根据Apple文档,Mac OS X中已弃用垃圾收集,而iOS中不存在垃圾收集。
罗勒·布尔克

4
“注意:属性原子性不是对象线程安全的同义词。” -来自developer.apple.com/library/mac/documentation/Cocoa/Conceptual/…–
jk7 2015年

1
“如果@property在头文件中使用声明了一个对象,则必须@synthesize在实现文件中使用进行合成。” 不总是。例如,“默认情况下,readwrite属性将由实例变量支持,实例变量将再次由编译器自动合成。” 来自doc
富兰克林于

4
@liza这是一个很好的答案。为什么这不是公认的答案。它传达的解释要比当前接受的答案要多得多。有时我不理解StackOverflow吗?
Charles Robertson

149

阅读许多文章后,我决定将所有属性信息放在一起:

  1. 原子//默认
  2. 非原子
  3. strong =保留//默认
  4. 弱=不安全不保留
  5. 保留
  6. 分配//默认
  7. unsafe_unretained
  8. 复制
  9. 只读
  10. readwrite //默认

下面是详细文章的链接,您可以在其中找到这些属性。

非常感谢在这里给出最佳答案的所有人!!

iOS中的可变属性属性或修饰符

这是文章中的样本描述

  1. atomic -Atomic表示仅一个线程访问该变量(静态类型)。-原子是线程安全的。-但是性能较慢-原子是默认行为-非垃圾回收环境中的原子访问器(即,使用保留/释放/自动释放时)将使用锁来确保另一个线程不会干扰正确的设置/获取价值。-它实际上不是关键字。

范例:

@property (retain) NSString *name;

@synthesize name;
  1. 非原子 -Nonatomic装置多线程访问的变量(动态型)。-Nonatomic是线程不安全的。-但是性能却很快-非原子不是默认行为,我们需要在属性属性中添加非原子关键字。-当两个不同的进程(线程)同时访问同一变量时,可能会导致意外行为。

例:

@property (nonatomic, retain) NSString *name;

@synthesize name;

说明:

假设有一个名为“ name”的原子字符串属性,并且如果您从线程A调用[self setName:@“ A”],则从线程B调用[self setName:@“ B”],然后从线程B调用[self name]线程C,然后对不同线程的所有操作将依次执行,这意味着如果一个线程正在执行setter或getter,则其他线程将等待。这使属性“名称”具有读/写安全性,但是如果另一个线程D同时调用[名称发布],则此操作可能会导致崩溃,因为此处不涉及setter / getter调用。这意味着一个对象是可读写的(ATOMIC)安全的,但不是线程安全的,因为另一个线程可以同时向该对象发送任何类型的消息。开发人员应确保此类对象的线程安全。

如果属性“名称”是非原子的,则上面示例中的所有线程-A,B,C和D将同时执行,从而产生任何不可预测的结果。在使用原子的情况下,A,B或C中的任何一个将首先执行,但D仍可以并行执行。

  1. 强大(iOS4 =保留)-它说:“将其保留在堆中,直到我不再指向它为止”-换句话说:“我是所有者,您不能在与保留相同的目的之前将其释放”仅在需要保留对象时才使用Strong。-默认情况下,所有实例变量和局部变量都是强指针。-我们通常对UIViewControllers(UI项的父项)使用“ strong”。-strong与ARC一起使用,它基本上可以帮助您,而不必担心对象的保留计数。完成后,ARC会自动为您释放它。使用关键字Strong意味着您拥有该对象。

例:

@property (strong, nonatomic) ViewController *viewController;

@synthesize viewController;
  1. (iOS4 = unsafe_unretained)-它表示“只要有人强烈指向它,请保持此状态”-与分配相同,不保留或释放-“弱”引用是您不保留的引用。-我们通常对IBOutlets(UIViewController的Childs)使用弱函数,这是有效的,因为子对象只需要与父对象一样存在即可。-弱引用是一种引用,它不能保护所引用的对象不受垃圾收集器的收集。-弱本质上是分配的,是未保留的属性。除了对象被释放时,弱指针会自动设置为nil

范例:

@property (weak, nonatomic) IBOutlet UIButton *myButton;

@synthesize myButton;

强而弱的解释,感谢BJ Homer

想象我们的对象是一只狗,那只狗想逃跑(被释放)。强壮的指针就像拴在狗身上的皮带。只要您将皮带拴在狗上,狗就不会跑开。如果有五个人将皮带拴在一只狗上(五个强力指针指向一个物体),则只有将所有五个皮带分开后,狗才会逃跑。另一方面,较弱的指针就像小孩指着狗说:“看!狗!” 只要这只狗仍系在皮带上,小孩子仍然可以看到它,他们仍会指向它。但是,一旦所有的皮带都松了,无论有多少小孩指向它,狗都会跑开。一旦最后一个强指针(皮带)不再指向对象,该对象将被释放,所有弱指针将被清零。什么时候用弱?您唯一想使用弱函数的情况是,如果您想避免保留周期(例如,父母保留了孩子,而孩子保留了父母,因此都不会被释放)。

  1. 保留 =强-保留,释放旧值并分配给它-保留指定要发送的新值-保留时赋值,并且发送的旧值-释放-保留与强相同。-apple说,如果您写保留,它将自动转换/像仅强一样工作。-“分配”之类的方法包含一个隐式的“保留”

例:

@property (nonatomic, retain) NSString *name;

@synthesize name;
  1. 分配 -assign是默认设置,只需执行一个变量赋值-assign是财产属性,它告诉编译器如何合成属性的setter的实现-我会用分配对C基本属性和弱弱引用Objective-C对象。

例:

@property (nonatomic, assign) NSString *address;

@synthesize address;
  1. unsafe_unretained

    -unsafe_unretained是所有权限定符,它告诉ARC如何插入保留/释放调用-unsafe_unretained是Assign的ARC版本。

例:

@property (nonatomic, unsafe_unretained) NSString *nickName;

@synthesize nickName;
  1. 当对象可变时,copy -copy是必需的。-copy指定在分配时应发送新值-copy,而旧值则发送-release。-copy就像保留返回一个对象,您必须在非垃圾收集环境中显式释放(例如,在dealloc中)。-如果使用copy,则仍需要在dealloc中释放它。-如果您现在需要该对象的值,并且不希望该值反映该对象的其他所有者所做的任何更改,请使用此值。完成对象后,您将需要释放它,因为您保留了副本。

例:

@property (nonatomic, copy) NSArray *myArray;

@synthesize myArray;

2
我认为弧线之后,保留不再使用。
mert 2014年

1
完整列表缺少2个选项项:setter和getter,这也是需要参数的唯一选项。
朱楚

仅对于对象类型,默认为“强”或“保留”。它不能用于基本类型。
Saleh Enam Shohag


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.