【iOS】属性关键字

【iOS】属性关键字

前言

属性关键字是我们iOS开发中非常重要的内容,这里我们需要经常性的去复习重新整理前面的内容,笔者之前已经学习过相关的内容,现在在这里重新介绍一遍相关的内容。iOS属性关键字和单例模式
有些重点内容就再介绍一次

属性关键字

@property, @synthesize, @dynamic

  • @property:这个可以理解为ivar + setter + getter 的一个合成,我们可以用@property这种语法来声明属性,他会帮我们生成上述三个类型
  • @synthesize:这是用于自动合成setter + getter方法的实现,现在的Xcode已经不需要这个关键字来帮助我们合成getter和setter方法了,他现在会自动生成相关的方法。这里注意可以通过这个来自己制定我们实例变量的名字

​ 这里要注意一下我们如果自己重写了setter或者getter方法的话,那么另一个还是会由编译器来直接实现,但是如果你实现了所以方 这里编译器就不会自动进行@synthesize,这时候就不会生成该属性的实例变量,需要自己手动@synthesize。

  • dynamic:这个是让我们的编译器不用自动进行@synathesize,我们会自己实现,无需产生警告,但是他不会影响@property生成的getter和setter方法的声明。这里其实体现了我们的OC是一种动态运行的语言,动态运行的语言将函数的决议推行到运行时。

分类中有关@property的使用

这里讲一下之前缺失的内容,分类中可以通过@property这个语法来给我们添加属性,但是这里不会生成对应的成员变量,我们不可以用@synathesize来合成成员变量的,这里笔者解释一下在分类中不能通过@synthesize来添加实例变量的原因:

  1. Category不能添加成员变量因为在运行期,对象的内存布局已经确定,如果添加实例变量会破坏类的内部布局),但是可以结合关联对象来为分类添加属性。(笔者这里对于有关关联对象的内容还不是很清楚,所以我准备后面在介绍相关内容)。
  2. @synthseize是用来合成成员变量的,而分类中不可以添加成员变量,所以我们不可以使用这种方式来添加成员变量

总体概述

这里笔者给出一个表格来进行一个总体的概述,先罗列出一个表格,方便对照。

关键字 解释
atomic 原子性访问,可以保证属性的赋值和取值的原子性操作是线程安全的。
nonatomic 非原子性,一般属性都用 nonatomic 进行修饰,因为 atomic 非常耗时。
readwrite 可读可写(默认),同时生成 setter 方法和 getter 方法的声明和实现。
readonly 只读,只生成 getter 方法的声明和实现。
strong 强引用,当一个对象被声明为strong属性,ARC会增加该对象的引用计数
weak 只能修饰对象类型;2. ARC 下才能使用;3. 修饰弱引用,不增加对象引用计数,主要可以用于避免循环引用;4. weak 修饰的对象在被释放之后,会自动将指针置为 nil,不会产生悬垂指针
assign 一般用于修饰基本类型; setter 方法的实现是直接赋值,一般用于基本数据类型 ; 修饰基本数据类型,如 NSInteger、BOOL、int、float 等;
copy 指定属性为拷贝引用,即属性会拷贝对象的值,而不是持有原始对象的引用
unsafe_unretained 基本和weak相似,但是他不会在该指针所引用的对象被回收后将指针赋为nil

较为重要的几个关键字

atomic和nonatomic

atomic:在OC中属性的默认声明为atomic,他可以保证对于属性的赋值和取值是一定线程安全的,但是如果对于数组这种对象的话他有存在问题,他对于数组对象的删除和添加操作是不安全的。保证读写操作的安全。
nonatomic:这个是不保证线程安全的,这个访问速度更快

assign 和 weak

这里最重要的内容是有关于我们对于delegate的修饰符应该采用那一个

  • 在ARC情况下我们一般使用的是weak这个关键字,这个关键可以避免被释放垂悬指针的问题
  • 在MRC情况下面我们采用这assign来修饰delegate,但是主要要自己手动释放。

这里一定不可以用strong来修饰代理,很容易就会出现一个循环引用的问题。

我们现在在ARC环境出来基本数据类型使用assign别的我们一般情况不使用,因为他很容易导致crash。

strong和copy

如果属性声明中指定了copy特性,合成方法会使用类的copy方法,这里注意:属性并没有mutableCopy特性。即使是可变的实例变量,也是使用copy特性,正如方法 copyWithZone:的执行结果。所以,按照约定会生成一个对象的不可变副本。

这里就是对于一个可变类型和不可变类型的选择问题了,我们以字符串类型来作为例子。

@interface Person : NSObject
@property (nonatomic, copy) NSString* name;
@property (nonatomic, assign) BOOL age;
@end

这里我们使用copy修饰符来修饰我们的NSString

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Person* p1 = [[Person alloc] init];
        NSMutableString *s1 = [NSMutableString stringWithString:@"nanxun"];
        p1.name = s1;
        [s1 appendString:@"911"];
        NSLog(@"%@", p1.name);
    }
    return 0;
}

这里的打印结果为:

在这里插入图片描述

但是如果我们使用strong去修饰NSString的话,他的结果为:

【iOS】属性关键字_第1张图片

这里引用一段学长的话:

因为s1是可变的,person.name属性是copy,所以创建了新的字符串,属于深拷贝,内容拷贝,我们拷贝出来了一个对象,后面的赋值操作都是针对新建的对象进行操作,而我们实际的调用还是原本的对象。所以值并不会改变。
如果设置为strong,strong会持有原来的对象,使原来的对象引用计数+1,其实就是浅拷贝、指针拷贝。这时我们进行操作,更改其值就使本对象发生了改变。

既然我们创建的是一个不可变类型,我们就尽量要让他不可变,所以对于不可变类型我们采用一个copy去修饰

如果是一个可变副本的话,我们采用copy标识符的话就会无法对于可变字符串进行一个修改的操作,

在这里插入图片描述

所以综上所述:对于可变类型采用strong,对于不可变类型采用copy。

你可能感兴趣的:(ios,cocoa,macos)