祖传财产!

对于Objective C类的starters属性而言,它是为实例变量以及最近为类成员定义getter和setter方法的简捷方法。 它们还帮助提供数据封装。

属性可用于定义实例变量或类变量的各个方面。
这些版本方面是
1.原子性
2.内存管理语义
3.可读性和可写性
4.存取器名称
5. Swift导入语义

只是为了演示属性包含的信息量,让我们定义一个简单的信息,然后尝试描述其实际含义。

  @property NSString *名称; 

它是原子的,强壮的,可读写的属性,将导致getter`name`和setter setName:`的合成,然后将其作为隐式展开的可选内容导入swift!

让我们谈谈这些方面的每一个。

有组织

任何属性都可以是原子的或非原子的。 通过getter访问原子属性时,它会返回该属性的有效值。 您可能想知道,getter应该返回一个有效值,什么是无效值? 在多线程环境中,当多个线程试图同时读取/写入属性时,指定属性为原子将确保在执行setter的过程中不会返回getter。 这意味着使用getter检索的值是在另一个线程执行写操作之前或之后,这仅保证该值不是无效或未完全写入。
这与线程安全性不同。
此外,在iOS平台上使属性原子化的成本非常高,因此很少使用此功能。 该实现使用自旋锁来确保多个线程不会同时读取写入。

内存管理语义

这些属性定义属性的设置方法在内存管理方面的行为。 即,当将新值设置为属性时,对象是否会被保留或复制或仅被分配。
在我们深入探讨此问题之前,您需要了解内存管理在ARC中的工作方式,本文不对此进行介绍。

属性的最重要属性是它的内存管理方面,您可以将任何属性指定为以下任一属性

  1. 分配
  2. 强大
  3. unsafe_unreatined
  4. 复制

让我们探索这些

  @属性(非原子的,分配)CGPoint中心; 
@属性(非原子,指定)CGFloat高度;

当setter只需要分配要设置的值时,可以使用assign。 这用于分配值类型,如上所述。 通常将值类型复制到目标变量,并且该值的生存期是该变量的范围。 对于指向在堆上为任何值类型或值类型的集合分配的内存的指针,需要调用显式的free,即需要手动管理内存。

  @property(nonatomic,weak)id 委托; 
@property(nonatomic,weak)id 数据源;

在上面的示例中,您看到了weak的使用,weak用于指定不保留分配的对象,相反,引用仅指向该对象,直到其有效为止,因此不影响该对象的寿命。 当属性保留对其的引用时,仍可以在任何时候释放该对象,如果引用弱,则在对象被取消初始化后,引用将指向nil。 自iOS 5 SDK以来,弱引用可用,在此之前,您可以使用unsafe_unretained来指定相同的行为,但是在取消初始化对象时,无需对引用进行零位或清零。
特别提到弱引用,它们在块的情况下用于捕获“ self”的值,以使该块最终不会对其捕获的对象具有潜在的保留周期。

  @属性(非原子的,强的)MYClass * someObject; 

指定强属性可确保设置器通过将保留计数增加1来将对象的所有权转让给引用,这意味着只要引用在范围内或显式设置为nil或其他值,对象就至少会存活。宾语。 我们通常为类的实例变量指定强引用,以便只要对象本身未取消初始化,它们所引用的对象即可保持活动状态。 当将强属性设置为新对象时,它所指向的先前对象将被释放,因此是否放弃所有权。

  @property(非原子的,副本)NSString * firstName; 
@property(非原子的,副本)NSString * lastName;

复制表示调用设置器时,将把对象的新副本设置为属性,而不是对象本身。 当您想要对象的不可变版本时,这真的很有用。 这可能与可变性(可读性/可写性)的概念混淆,但是它完全不同,一旦我们讨论了只读和可写,我们将对其进行讨论。
为了可复制,对象的类需要符合NSCopying协议,并且协议“ copyWithZone:”中的唯一方法将在对象上调用以获取副本。

  @property(nonatomic,unsafe_unreatained)id 委托 

此属性与弱属性相同,除了在释放对象时这些引用不会为零或设置为nil之外。 引用归零是在Obj C运行时中实现的功能,可用于iOS 5 SDK。
当您使用unsafe_unretained时,它不会增加所设置对象的保留计数,因此不会影响该对象的生存期。
尽管此属性的缺点是,如果在释放对象之后在此属性上调用了任何方法,则程序可能会崩溃,这与弱引用的情况不同。 但是在以下情况下使用unsafe_unretained
您可以确保在引用超出范围之前不会释放对象对象,这在性能方面具有优势,因为将引用清零会占用大量内存。 在弱引用的情况下,对引用的延迟为零,对象或对象的一部分保留在内存中,直到所有弱引用都为零。

属性的可变性或可读性/可写性

  @property(非原子,只读,副本)NSString * firstName; 
@property(非原子,只读,强)NSString * lastName;
@property(非原子的,强的)MYClass * obj;

readonly指定该引用不得指向任何其他对象,并且一旦初始化就不得更改。 这里的关键点很少,只读属性只能在初始化期间设置,并且在初始化期间,您必须限制使用属性设置器,而不能直接使用backing变量。
即,在上面的示例中,您应该直接在init方法中使用变量_firstName来设置名字的值,并确保使用所设置的值的副本像这样来初始化_firstName

  -(instancetype)initWithFirstName:(NSString *)name { 
如果(自我= [超级初始化]){
_firstName = [名称副本];
}
}

指定readonly属性将确保该属性仅合成一个getter,该技术可用于从公共接口隐藏setter。 然后,您可以在类连续类别中定义一个属性,以
让该属性在类中进行更改。

现在让我们讨论复制和只读,假设我们已经声明了这样的姓氏
@property(nonatomic, readonly, strong) NSString *lastName;
尽管该属性不允许修改对象,因为未合成setter,但由于未复制该属性,因此可以从其下方更改其指向的实际对象,这并不是我们想要的,特别是如果有名字name
我们不希望有人在不知情的情况下更改我们的名字。 因此,在适当的情况下使用副本确实有帮助。

存取器名称

属性还可以让您指定getter和setter的名称,默认情况下,getter的名称与属性相同,setter的名称为驼峰式,带有“ set”前缀。
例如:
@property(nonatomic, strong) MYClass *obj;
得到
— (MYClass*)obj
作为吸气剂和
— (void)setObj:(MYClass*)obj
作为二传手。

您可以通过在属性声明中指定getter和setter名称来更改默认行为。
@property(nonatomic, strong, getter=getObj, setter = setMyObj:) MYClass *obj;
这里将有两种方法getObjsetMyObj:合成而不是默认方法。

除了附件名称,您还可以更改综合变量的默认名称,例如,在上面的示例中,_obj将是变量的默认名称,但是您可以通过定义
@synthesis obj = _myobj;
在执行该类。

Swift导入语义

默认情况下,所有对象属性都作为隐式未包装的可选内容导入到swift中。 要更改此默认行为,您可以指定属性是否可以为null,而swift会将其推断为可选变量或非可选变量。

让我们看一些例子

  NS_ASSUME_NONNULL_BEGIN @ interface TTTest:NSObject @ property(非原子,强壮,getter = getName,setter = setmycustomName :) NSString * name;-(instancetype)initWithFirstName:(NSString *)name; @endNS_ASSUME_NONNULL_END 

您可以使用NS_ASSUME_NONNULL_STARTNS_ASSUME_NONNULL_END定义如何快速导入成员的默认行为。
对于每个目标C文件,您都可以查看一个swift标头,其中显示了如何将目标C类型导入swift。 上面界面的swift标头看起来像这样

 打开类TTTest:NSObject {打开变量名称:Stringpublic init(firstName名称:String)} 

注意:有趣的是,swift接口会忽略getter和setter属性,而只公开名称。

您可以看到变量name和init方法都具有非可选类型。 与此相反,如果未声明NS_ASSUME_NONNULL,则任何变量或参数或返回值都将作为显式展开的可选项导入。 在这种情况下,界面就是这样

 打开类TTTest:NSObject {打开变量名:String!public init!(名字:String!)} 

非常感谢使用NS_ASSUME_NONNULL_BEGIN和END,因为如果您有选择地将每个属性,ivar或返回类型定义为nonnull或nullable,则必须对所有可能的符号进行操作,否则xcode将向您显示警告。 通过使用NS_ASSUME_NONNULL_BEGIN,您可以定义默认行为,并专门使任何符号为nullable以将其作为可选内容导入到Swift中。

您可以通过切换到助手编辑器来查看目标c类的swift接口文件,然后在其中选择计数器部件作为swift接口。

这是GitHub链接,其中包含有关属性工作原理以及其原子性部分的演示。 希望对了解祖先目标C属性有帮助。

参考文献
https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/EncapsulatingData/EncapsulatingData.html

https://mikeash.com/pyblog/friday-qa-2015-12-11-swift-weak-references.html