@property在Objective-C中保留,赋值,复制,非原子

Mar*_*eid 211 iphone memory-management objective-c ios

作为Objective-C的新手,有人可以按照@property指令给我一个概述保留,分配,复制和我缺少的任何其他内容吗?他们在做什么,为什么我要用另一个?

liz*_*iza 294

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

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

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

  • 访问器方法有:setter和getter.

示例:.h

@interface XYZClass : NSObject
@property (nonatomic, retain) NSString *name;
@end
Run Code Online (Sandbox Code Playgroud)

.M

@implementation XYZClass
@synthesize name;
@end
Run Code Online (Sandbox Code Playgroud)

现在编译器将合成name的访问器方法.

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

    atomic,nonatomic,retain,copy,readonly,readwrite,assign,strong,getter = method,setter = method,unsafe_unretained

  • atomic是默认行为.如果一个对象被声明为原子,那么它就变成了线程安全的.线程安全意味着,该类的特定实例中只有一个线程可以控制该对象.

如果线程正在执行getter方法,则其他线程无法对该对象执行setter方法.这很慢.

@property NSString *name; //by default atomic`
@property (atomic)NSString *name; // explicitly declared atomic`
Run Code Online (Sandbox Code Playgroud)
  • 非原子 不是线程安全的.您可以使用非原子属性属性来指定合成访问器直接设置或直接返回值,而不保证如果从不同线程同时访问相同的值会发生什么.

因此,访问非原子属性比原子属性更快.

@property (nonatomic)NSString *name;   
Run Code Online (Sandbox Code Playgroud)
  • 当属性是指向对象的指针时,需要retain.

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

@property (retain)NSString *name;
Run Code Online (Sandbox Code Playgroud)
  • copy如果使用copy,则不能使用retain.使用该类的副本实例将包含其自己的副本.

即使设置了一个可变字符串并随后进行了更改,该实例也会捕获它在设置时所具有的任何值.不会合成任何setter和getter方法.

@property (copy) NSString *name;
Run Code Online (Sandbox Code Playgroud)

现在,

NSMutableString *nameString = [NSMutableString stringWithString:@"Liza"];    
xyzObj.name = nameString;    
[nameString appendString:@"Pizza"]; 
Run Code Online (Sandbox Code Playgroud)

名称将不受影响.

  • readonly如果您不想通过setter方法允许更改属性,则可以只读取属性readonly.

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

@property (readonly) NSString *name;
Run Code Online (Sandbox Code Playgroud)
  • readwrite是默认行为.您不需要显式指定readwrite属性.

它与readonly相反.

@property (readwrite) NSString *name;
Run Code Online (Sandbox Code Playgroud)
  • assign将生成一个setter,它直接将值赋给实例变量,而不是复制或保留它.这最适用于NSInteger和CGFloat等原始类型,或者您不直接拥有的对象,例如委托.

请记住,启用垃圾收集时,retain和assign基本上是可互换的.

@property (assign) NSInteger year;
Run Code Online (Sandbox Code Playgroud)
  • 强者是保留的替代品.

它配有ARC.

@property (nonatomic, strong) AVPlayer *player; 
Run Code Online (Sandbox Code Playgroud)
  • getter = method如果要为getter方法使用不同的名称,可以通过向属性添加属性来指定自定义名称.

在布尔属性(具有YES或NO值的属性)的情况下,getter方法通常以单词"is"开头

@property (getter=isFinished) BOOL finished;
Run Code Online (Sandbox Code Playgroud)
  • setter = method如果要为setter方法使用不同的名称,可以通过向属性添加属性来指定自定义名称.

该方法应以冒号结束.

@property(setter = boolBool:) BOOL finished;
Run Code Online (Sandbox Code Playgroud)
  • unsafe_unretained有可可和可可触摸几类,还不支持弱引用,这意味着你不能声明弱属性或弱的局部变量来跟踪它们.这些类包括NSTextView,NSFont和NSColorSpace等.如果需要对这些类之一使用弱引用,则必须使用不安全的引用.

不安全引用类似于弱引用,因为它不保持其相关对象存活,但如果目标对象被释放,则不会将其设置为nil.

@property (unsafe_unretained) NSObject *unsafeProperty;
Run Code Online (Sandbox Code Playgroud)

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

@property (readonly, getter=isFinished) BOOL finished;
Run Code Online (Sandbox Code Playgroud)

  • 忽略有关垃圾收集的答案中的行,因为垃圾收集在Mac OS X中已弃用,在iOS中不存在[Apple文档](https://developer.apple.com/library/mac/releasenotes/ObjectiveC/RN -TransitioningToARC /介绍/ Introduction.html#// apple_ref/DOC/UID/TP40011226-CH1-SW17). (6认同)
  • "注意:属性原子性与对象的线程安全性不是同义词." - 来自https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/EncapsulatingData/EncapsulatingData.html#//apple_ref/doc/uid/TP40011210-CH5-SW4 (4认同)
  • @liza这是一个很好的答案.为什么这不是公认的答案.它传达了比目前接受的答案更为知识渊博的解释.我有时不了解StackOverflow? (4认同)

Bla*_*rot 271

由MrMage链接的文章已不再有效.所以,这是我在Objective-C的(非常)短时间编码中学到的:

非原子与原子 - "原子"是默认值.始终使用"非原子".我不知道为什么,但我读过的那本书说"很少有理由"使用"原子".(顺便说一句:我读过的书是BNR"iOS编程"一书.)

readwrite与readonly - "readwrite"是默认值.@synthesize时,将为您创建一个getter和一个setter.如果使用"readonly",则不会创建setter.将它用于在对象实例化后不希望更改的值.

保留与复制与分配

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

  • "总是使用非原子"是不好的建议.当你使用非原子时,你应该知道你放弃了什么. (51认同)
  • @Odelya - 不会.如果您在使用ARC时发布,我相信您会收到编译错误. (10认同)
  • 建议保留默认的`atomic`与建议`nonatomic`一样糟糕.两种选择都不是"正确的",因此语言设计者选择了两种解决方案更安全.事实上,`nonatomic`通常是更好的选择,因为它省略了极其昂贵的线程锁.使用`atomic`的唯一原因是,如果您的属性可能是从多个线程设置的(在这种情况下省略它可能导致过度释放或泄漏). (8认同)
  • 同意.特别是,许多人似乎并不知道非原子值不会被吸气剂自动释放.非原子通常是合适的,但货物崇拜编程很少. (7认同)
  • 自Xcode 4.3 for ARC以来,Strong是默认值 (6认同)

swi*_*Boy 147

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

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

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

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

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

以下是文章中的示例说明

  1. atomic -Atomic意味着只有一个线程访问变量(静态类型).-Atomic是线程安全的. - 但它的性能很慢 - 原子是默认行为 - 非垃圾收集环境中的原子访问器(即使用retain/release/autorelease时)将使用锁来确保另一个线程不会干扰正确的设置/获取的价值.-it实际上不是关键字.

示例:

@property (retain) NSString *name;

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

例:

@property (nonatomic, retain) NSString *name;

@synthesize name;
Run Code Online (Sandbox Code Playgroud)

说明:

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

如果属性"name"是非原子的,那么上面例子中的所有线程--A,B,C和D将同时执行,产生任何不可预测的结果.在原子的情况下,A,B或C中的任何一个将首先执行,但D仍然可以并行执行.

  1. 强大的(iOS4 =保留) - 它说"把它保留在堆中,直到我不再指向它" - 换句话说"我是主人,你不能解除这个,然后瞄准好与保留相同" -仅在需要保留对象时才使用strong. - 默认情况下,所有实例变量和局部变量都是强指针. - 我们通常使用强大的UIViewControllers(UI项目的父母)-strong与ARC一起使用,它基本上可以帮助你,而不必担心对象的保留计数.完成后,ARC会自动为您释放它.使用关键字strong表示您拥有该对象.

例:

@property (strong, nonatomic) ViewController *viewController;

@synthesize viewController;
Run Code Online (Sandbox Code Playgroud)
  1. (iOS4 = unsafe_unretained)-it表示"只要其他人强烈指向它就保持这个" - 与分配相同,不保留或释放 - "弱"引用是您不保留的引用. - 我们通常对IBOutlets使用弱(UIViewController的Childs).这是有效的,因为只要父对象存在,子对象才需要存在.弱引用是一种引用,它不保护引用的对象不被垃圾收集器收集.-Weak本质上是分配,一个没有保留的属性.除了取消分配对象时,弱指针自动设置为nil

示例:

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

@synthesize myButton;
Run Code Online (Sandbox Code Playgroud)

强烈而微弱的解释,感谢BJ荷马:

想象一下,我们的对象是一只狗,狗想要逃跑(被解除分配).强壮的指针就像是狗的皮带.只要你的皮带附着在狗身上,狗就不会逃跑.如果五个人将他们的皮带连接到一只狗,(五个强指针指向一个物体),那么在所有五个皮带脱落之前,狗不会逃跑.另一方面,弱点就像小孩子指着那只狗说"看!一只狗!" 只要狗仍然在皮带上,小孩子仍然可以看到狗,他们仍然会指向它.然而,一旦所有的皮带脱落,无论有多少小孩指着它,狗都会跑开.一旦最后一个强指针(皮带)不再指向一个对象,该对象将被释放,并且所有弱指针都将被清零.当我们使用弱者?你想要使用弱的唯一一次是,如果你想避免保留周期(例如父母保留孩子而孩子保留父母,所以两者都没有被释放).

  1. retain = strong -it被保留,旧值被释放并且被赋值-retain指定新值应该在发送时发送-retain并且发送的旧值-release -retain与strong相同.-apple说如果你写保留它会自动转换/工作只有强大.像"alloc"这样的方法包含一个隐含的"保留"

例:

@property (nonatomic, retain) NSString *name;

@synthesize name;
Run Code Online (Sandbox Code Playgroud)
  1. assign -assign是默认值,只是执行变量赋值-assign是一个属性属性,它告诉编译器如何合成属性的setter实现 - 我将使用assign来表示C原语属性而weak表示弱对Objective-C对象的引用.

例:

@property (nonatomic, assign) NSString *address;

@synthesize address;
Run Code Online (Sandbox Code Playgroud)
  1. unsafe_unretained

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

例:

@property (nonatomic, unsafe_unretained) NSString *nickName;

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

例:

@property (nonatomic, copy) NSArray *myArray;

@synthesize myArray;
Run Code Online (Sandbox Code Playgroud)

  • 我认为在弧之后,不再使用保留. (2认同)

Kan*_*sad 9

原子属性一次只能由一个线程访问.它是线程安全的.默认是原子的.请注意,没有关键字 原子

Nonatomic意味着多个线程可以访问该项.它是线程不安全的

因此在使用原子时应该非常小心.因为它会影响代码的性能

  • "注意:属性原子性与对象的线程安全性不是同义词." 来自https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/EncapsulatingData/EncapsulatingData.html#//apple_ref/doc/uid/TP40011210-CH5-SW4 (3认同)