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

objectivec 复制代码
@property (nonatomic,copy) NSString *str;

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

1.2synthesize

objectivec 复制代码
#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方法不会进行加锁操作。其内部的具体实现如下:

objectivec 复制代码
@property (nonatomic,strong) UIImage *image0;
objectivec 复制代码
@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方法会进行加锁操作。其内部的具体实现如下:

objectivec 复制代码
@property (atomic,strong) UIImage *image1;
objectivec 复制代码
@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的有一个关键语句:

objectivec 复制代码
_copyyStr = [copyyStr copy];

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

objectivec 复制代码
@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 中。
相关推荐
HarderCoder28 分钟前
iOS 知识积累第一弹:从 struct 到 APP 生命周期的全景复盘
ios
叽哥11 小时前
Flutter Riverpod上手指南
android·flutter·ios
用户091 天前
SwiftUI Charts 函数绘图完全指南
ios·swiftui·swift
YungFan1 天前
iOS26适配指南之UIColor
ios·swift
权咚2 天前
阿权的开发经验小集
git·ios·xcode
用户092 天前
TipKit与CloudKit同步完全指南
ios·swift
法的空间2 天前
Flutter JsonToDart 支持 JsonSchema
android·flutter·ios
2501_915918412 天前
iOS 上架全流程指南 iOS 应用发布步骤、App Store 上架流程、uni-app 打包上传 ipa 与审核实战经验分享
android·ios·小程序·uni-app·cocoa·iphone·webview
00后程序员张3 天前
iOS App 混淆与加固对比 源码混淆与ipa文件混淆的区别、iOS代码保护与应用安全场景最佳实践
android·安全·ios·小程序·uni-app·iphone·webview
Magnetic_h3 天前
【iOS】设计模式复习
笔记·学习·ios·设计模式·objective-c·cocoa