ChatGPT解决这个技术问题 Extra ChatGPT

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

作为 Objective-C 的新手,谁能给我一个关于保留、分配、复制和我缺少的任何其他遵循 @property 指令的概述?他们在做什么,为什么我要使用一个而不是另一个?

苹果对这些的名称是“属性”或“属性属性”

l
liza

在了解@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 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`

非原子不是线程安全的。您可以使用非原子属性来指定合成访问器直接设置或返回一个值,而不保证如果从不同线程同时访问相同的值会发生什么。

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

@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 方法更改属性,则可以将属性声明为只读。

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

@property (readonly) NSString *name;

读写是默认行为。您不需要明确指定 readwrite 属性。

它与只读相反。

@property (readwrite) NSString *name;

assign 将生成一个设置器,该设置器将值直接分配给实例变量,而不是复制或保留它。这对于 NSInteger 和 CGFloat 等原始类型或您不直接拥有的对象(例如委托)是最好的。

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

@property (assign) NSInteger year;

strong 是保留的替代品。

它带有 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;

此外,weak 表示对所引用对象没有引用计数,而是根本没有引用它,或者根本没有引用它。有点像“是的,引用了我的东西”与“存在 9 个对我的引用”(这就是强大的东西)。
忽略答案中关于垃圾收集的行,因为垃圾收集在 Mac OS X 中已被弃用,而在 iOS 中每个 Apple documentation 中不存在垃圾收集。
“注意:属性原子性不是对象的线程安全的同义词。” - 来自developer.apple.com/library/mac/documentation/Cocoa/Conceptual/…
“如果您在头文件中使用 @property 声明一个对象,那么您必须在实现文件中使用 @synthesize 合成它。”不总是。例如,“默认情况下,readwrite 属性将由实例变量支持,该变量将再次由编译器自动合成。”从 doc
@liza 这是一个很好的答案。为什么这不是公认的答案。它传达了比当前接受的答案更博学的解释。我有时不明白 StackOverflow?
B
Blamdarot

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

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

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

保留 vs. 复制 vs. 分配

“分配”是默认值。在@synthesize 创建的setter 中,值将简单地分配给属性。我的理解是“分配”应该用于非指针属性。

当属性是指向对象的指针时,需要“保留”。 @synthesize 生成的 setter 将保留(也就是添加保留计数)对象。完成后,您将需要释放该对象。

当对象是可变的时,需要“复制”。如果您现在需要对象的值,并且您不希望该值反映对象的其他所有者所做的任何更改,请使用此选项。完成后您将需要释放该对象,因为您保留了副本。


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

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

atomic //默认非原子 strong=retain //默认 weak= unsafe_unretained retain assign //默认 unsafe_unretained copy readonly readwrite //default

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

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

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

这是文章中的示例描述

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

例子 :

@property (retain) NSString *name;

@synthesize name;

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

例子:

@property (nonatomic, retain) NSString *name;

@synthesize name;

解释:

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

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

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

例子:

@property (strong, nonatomic) ViewController *viewController;

@synthesize viewController;

弱(iOS4 = unsafe_unretained)-它说“只要其他人强烈指向它就保留它”-与分配相同,不保留或释放-“弱”引用是您不保留的引用。 - 我们通常对 IBOutlets(UIViewController 的 Childs)使用weak。这是因为子对象只需要与父对象一样存在。 - 弱引用是不保护被引用对象不被垃圾收集器收集的引用。 -Weak 本质上是赋值,一个未保留的属性。除了当对象被释放时,弱指针自动设置为 nil

例子 :

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

@synthesize myButton;

强&弱解释,Thanks to BJ Homer

想象我们的对象是一只狗,而这只狗想要逃跑(被释放)。强指针就像狗的皮带。只要你把皮带拴在狗身上,狗就不会逃跑。如果五个人将他们的皮带拴在一只狗身上(五个强指针指向一个物体),那么在所有五根皮带都脱离之前,狗不会逃跑。另一方面,弱指针就像小孩子指着狗说“看!一条狗!”只要狗还在皮带上,小孩子仍然可以看到狗,他们仍然会指向它。然而,一旦所有的皮带都松开了,不管有多少小孩指着它,狗都会跑掉。一旦最后一个强指针(leash)不再指向一个对象,这个对象就会被释放,所有的弱指针都会被清零。当我们使用弱?您唯一想使用弱的情况是,如果您想避免保留循环(例如,父母保留孩子,孩子保留父母,因此两者都不会被释放)。

retain = strong - 保留,释放旧值并分配 -retain 指定应发送新值 -retain 分配时发送旧值 -release -retain 与 strong 相同。 -apple 说如果你写保留它只会自动转换/像强一样工作。 - 像“alloc”这样的方法包括一个隐含的“retain”

例子:

@property (nonatomic, retain) NSString *name;

@synthesize name;

assign -assign 是默认值,只是执行变量赋值 -assign 是一个属性属性,它告诉编译器如何合成属性的 setter 实现 -我将 assign 用于 C 原始属性,weak 用于对 Objective-C 对象的弱引用。

例子:

@property (nonatomic, assign) NSString *address;

@synthesize address;

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

例子:

@property (nonatomic, unsafe_unretained) NSString *nickName;

@synthesize nickName;

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

例子:

@property (nonatomic, copy) NSArray *myArray;

@synthesize myArray;

我认为在弧之后,不再使用保留。
完整列表缺少 2 个选项项:setter 和 getter,它们也是唯一需要参数的选项。
strong 或 retain 仅适用于对象类型。它不能用于原始类型。
K
Kannan Prasad

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

非原子意味着多个线程可以访问该项目。它是线程不安全的

所以在使用 atomic 时应该非常小心。因为它会影响代码的性能


“注意:属性原子性不是对象的线程安全的同义词。”来自developer.apple.com/library/mac/documentation/Cocoa/Conceptual/…
A
Ahmad Abbas

更喜欢这个关于iOS中objective-c中属性的链接......

https://techguy1996.blogspot.com/2020/02/properties-in-objective-c-ios.html