自学内容网 自学内容网

iOS ------ 关键字

关键字可以分为以下六类

  • 修饰器类型:@property、@synthesize、@dynamic
  • 原子安全类型: nonatomic、atomic
  • 计数引用类型: strong、weak、assign、copy、retain、unsafe_unretained
  • 读写类型:readonly,readwrite
  • 访问类型:extern、static、const
  • 局部引用类型:__weak、__block、__strong

1、修饰器类型:@property、@synthesize、@dynamic

1.1@property

@property (nonatomic,copy) NSString *str;

用来声明属性,相当于声明了_str,并且默认实现了str的getter和setter方法

1.2synthesize

#import "ClassA.h"

@interface ClassA()

@property NSString * str3;

@end

@implementation ClassA
// 或者写成 @synthesize str3
@synthesize str3 = str4;

@end

@synthesize要用的话,必须得声明了同名的属性,例如我已经声明了str3,再用@synthesize声明str3,那么就相当于编译器默认生成了一个str3属性和一个str3成员变量.str3的getter个setter实际上操作的都是str4

1.3@dynamic

@dynamic声明属性就相当于告诉编译器不用生成属性的getter和setter方法,该属性的getter和setter方法由我自己生成

2、原子安全类型: nonatomic、atomic

这两个类型就是跟线程相关的,atomic与nonatomicd的主要区别就是系统自动生成的getter/setter方法不一样。

2.1、nonatomic

nonatomic(默认情况)表示非原子属性,也就是线程不安全类型,系统自动生成的getter/setter方法不会进行加锁操作。其内部的具体实现如下:

@property (nonatomic,strong) UIImage *image0;
@synthesize image0 = _image0;
/// MRC模式下

- (UIImage *)image0{
    return _image0;
}

- (void)setImage0:(UIImage *)image0 {
    if (_image0 != image0) {
        [_image0 release];
        _image0 = [[image0 retain] autorelease];
    }
}

2.2、atomic

atomic表示原子属性,表示线程安全,系统自动生成的getter/setter方法会进行加锁操作。其内部的具体实现如下:

@property (atomic,strong) UIImage *image1;
@synthesize image1 = _image1;
/// MRC模式下

- (UIImage *)image1 {
    @synchronized (self) {
        return _image1;
    }
}

- (void)setImage1:(UIImage *)image1 {
    @synchronized (self) {
        if (_image1 != image1) {
            [_image1 release];
            _image1 = [[image1 retain]autorelease];
        }
    }
}

atomic修饰的属性也不一定安全,当修饰NSMutableArray时,当我们进行removeadd的时候,此时也不是线程安全的,它不是原子操作。它保证的是gettersetter的线程安全。

3、计数引用类型: strong、weak、assign、copy、retain、unsafe_unretained

3.1 strong

当使用strong关键字修饰一个属性时,该属性不仅指向该对象,而且拥有该对象。该对象的引用计数会加1,属于强引用用。在ARC环境下,相当于retain。也称为浅拷贝(指针拷贝)。内存地址不变,只是生成了一个新的指针,新指针和引用对象的指针指向同一个地址。

注意:因为使用的是同一个内存地址,当该内存地址存储的内容发生变更的时候。属性也会变更。

3.2weak

同样经常用于修饰OC对象类型的数据,修饰的对象在释放后,指针地址会自动被置为nil,这是一种弱引用。

注意:在ARC环境下,为了避免循环引用,会把delegate属性用weak修饰,在MRC环境下使用assign修饰。当一个strong类型的指针不在指向它的时候,它就会被释放,即使还有weak的指针指向他,这些weak指针也会被值为nil。

weak属性修饰的变量,如何实现在变量没有强引用后自动置为 nil ?

runtime 维护了一个weak_table_t 弱引用表
,用于存储指向某一个对象的所有weak指针。weak表其实是一个哈希表,key是所指对象的地址,value是weak指针的地址的数组。在对象回收的时候,根据对象的地址将所有weak指针地址的数组,遍历数组把其中的数据置为nil。

3.3 assign

一般用来修饰非指针变量,用于基础数据类型 (例如NSInteger)和C数据类型(int, float, double, char, 等),另外还有id类型。也可用来修饰对象,但被assign修饰的额对象被释放后后,指针还是指针对象之前的地址,就变成了野指针。(如果用了assign修饰的对象,需要在dealloc函数中将该对象指针手动值为nil,可以消除野指针。

3.4 copy

copy和strong相同点在于都是属于强引用,都会是属性的计数加一,但是copy和strong不同点在于,它所修饰的属性当引用一个属性值时,是内存拷贝(深拷贝),就是在引用是,会生成一个新的内存地址和指针地址来,和引用对象完全没有相同点,因此它不会因为引用属性的变更而改变(当引用的属性值是不可变对象时,是浅拷贝)

具体的用例可以参考:strong和copy的区别

copy修饰的关键字不同在于属性setter的有一个关键语句:

_copyyStr = [copyyStr copy];

所以只有在用点语法赋值时copy关键字才会生效

@property (copy) NSMutableString* name;

如果用copy来修饰NSMutableArrayNSMutableDictionaryNSMutableString这种不可变对象会导致问题,初始化后通过copy生成的是该类型对应的不可变对象,例如NSArrayNSDictionaryNSString。如果我们按照可变对象进行修改属性操作,就有可能报错。

3.5 retain

retain主要用在MRC模式下,作用和strong几乎等同

3.6 unsafe_unretained

unsafe_unretained类型指针指向一块内存时,内存的引用计数也不会增加,这一点与weak一致。但是与weak类型不同的是,当其所指向的内存被销毁时,unsafe_unretained类型的指针并不会被赋值为nil,也就是变成了一个野指针。对野指针指向的内存进行读写,程序就会crash

4,读写类型 readonly readwrite

4.1 readonly

readonly相当于是系统只会默认生成该属性的getter方法,只可读不可写,用点属性的形式去赋值,那么就会编译报错。

如果是在该类的外部访问readonly属性,利用kvc直接赋值。可以通过在类的内部重写accessInstanceVariablesDirectly,固定返回No,那么外界就无法再通过kvc形式来更改

4.2 readwrite

readwrite就是声明该属性可读可写,一般默认就是readwrite,可以不用额外声明

5, 访问类型

5.1 extern

对于跨文件访问全局变量需要借助extern关键字声明,通过extern有两种方式可以访问其他文件的全局变量。

方式一
我们想要在B类访问A类中声明和定义的全局变量时,不导入A类的头文件,在B类中使用extern声明A类中的全局变量

方式二
我们在A.m文件中声明和定义的全局变量时,同时在A.h文件中做extern声明,在B类访问A类中全局变量时导入A的头文件就可以了,这种方式在代码中比较常见。

5.2 static

static除了可以修饰全局变量,还可以修饰局部变量,被static修饰的变量叫做静态变量。

主要作用:

  • 隐藏
    当程序有多个文件时,将全局变量或函数的作用域的作用范围限制在当前文件,对其他文件隐藏
  • 保持变量内容的持久化
    将函数的局部变量储存在全局数据区,使它不会随着函数的调用结束而被销毁

5.3 const

const用于修饰指针变量和基本数据类型,const放在谁前面,谁就是常量不可在更改。

不管是extern声明的全局变量还是用staticconst修饰的全局变量和局部变量,它们的生命周期都是从定义到程序结束。

6,局部引用类型:__weak,__strong,__unsafe_unretained,__autoreleasing

  • __strong
    1. 强引用持有对象,可以对应 strong、retain、copy 关键字。
    1. 编译器将为 strong、retain、copy 修饰的属性生成带 __strong 所有权修饰符的实例变量.
  • __weak
    1. 弱引用持有对象,对应 weak 关键字,ARC下用来防止循环引用。
    1. 编译器将为 weak 修饰的属性生成带 __weak 所有权修饰符的实例变量。
  • __unsafe_unretained
    1. 弱引用持有对象,对应 unsafe_unretained、assign 关键字,MRC下用来防止循环引用。
    1. 编译器将为 unsafe_unretained 修饰的属性生成带 __unsafe_unretained 所有权修饰符的实例变量。
    1. 与 __weak 相比,它不需要遍历 weak 表来检查对象是否 nil,性能上要更好一些。但是它会产生悬垂指针
  • __autoreleasing
    +在 MRC 中我们可以给对象发送 autorelease 消息来将它注册到 autoreleasepool 中,而在 ARC 中我们可以使用 __autoreleasing 修饰符修饰对象将对象注册到 autoreleasepool 中。

原文地址:https://blog.csdn.net/m0_73974056/article/details/140619625

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!