当前位置: 首页 > news >正文

【OC】属性关键字

文章目录

  • 前言
  • 属性关键字
    • @property
    • @synthesize
    • @dynamic
    • 原子操作
      • atomic
      • nonatomic
    • 读写权限
      • readwrite
      • readonly
    • 内存管理
      • weak
      • assign
      • retain
      • strong
      • copy
      • copy和strong对比
  • 深浅拷贝
    • 容器类对象的深拷贝
      • 完全深拷贝
      • 递归深拷贝
  • 总结

前言

属性关键字是oc中基础且相当重要的知识点,之前学的时候有所接触但学的没有那么深入,这次便深入介绍一下其相关内容

属性关键字

@property

用来声明属性,编译器会默认:

  1. 自动生成一个实例变量(ivar),名字为**_属性名**
  2. 自动生成对应的getter/seter方法的声明与实现

@synthesize

以前必须写这个才能生成该实例变量与对应的方法,现在现在只需要经过@property声明,编译器便可以自动合成实例变量和方法。

  • 现在可以通过这个来自定义实例变量的名字
@synthesize name = _myName; // 属性name对应的ivar叫_myName

@dynamic

这个是让我们的编译器不用自动进行@synthesize,其不会影响到@property所自动生成的getter,setter方法的声明。

编译器会自动帮我们生成实例变量和存取方法,但是还有几个得写@synthesize的例外:

  • 如果我们自己实现了getter和setter,就不会自动帮我们生成,若我们想要一个ivar,就需要@synthesize
  • 若该属性为readonly,且我们自己写了getter,若我们想要一个ivar,就需要@synthesize
  • 在协议里的属性,协议只声明,不会生成ivar,所以在遵循协议的类里,若我们要ivar,则必须要@synthesize,不写@synthesize,就必须自己实现setter与getter,否则编译报错

原子操作

属性是否有原子性可以理解为线程是否安全

atomic

原子性,加同步锁,是默认的修饰符,用这个会消耗性能,仅可以保证单词访问是原子的,且不一定能保证线程安全,若想保证线程安全,可以用其他锁的机制(此处涉及到了多线程的部分知识,以后学习之后再进行补写)

nonatomic

非原子性,无同步保护,声明属性时基本为这个,可以提高访问性能

读写权限

默认为readwrite

readwrite

可读可写,属性拥有setter和getter方法

readonly

只读,仅提供了getter方法

内存管理

weak

只可用来修饰对象类型,ARC下才可以使用来修饰弱引用,不增加所修饰对象的引用计数,主要可以用来避免循环引用,所修饰的对象被释放后,会自动将指针指向nil,不会产生悬垂指针(即指向已被释放或者无效的指针)

assign

一般用于修饰基本数据类型(也可以用来修饰对象,但是在销毁时可能会产生悬垂指针,从而出现crash,即程序崩溃),setter方法是实现直接赋值,修饰如NSInteger,BOOL,int,float等的基本数据类型,且使用其修饰对象时时也不增加引用计数

retain

在MRC下使用,现在ARC下基本使用strong,主要用来修饰强引用,会增加引用计数,原理是用release释放之前的旧值,并调用retain,引用计数+1,最后再设置新值把原指针指向新的对象,现在基本不用所以不给出详解

strong

在ARC下使用,用来修饰强引用,原理与retain一样,但是ARC下编译器帮我们做了retain+release的操作

在修饰block时,strong相当于copy,retain相当于assign,原理如下:

block在内存中区域比较独特,在创建时其位于栈区,是临时的,函数返回后即会被销毁,但是在copy或者ARC下的strong修饰后会把block从栈区拷贝到堆区,类似于普通对象一样,可受到引用计数的管理,且只要强引用持有,其就会一直存在

copy

指定属性为拷贝对象的引用,而不是引用所拷贝的原始的对象

copy和strong对比

copy:深拷贝,内存地址不同,指针地址不同,release旧值,copy新值

strong:浅拷贝,内存地址不变指针地址不同

若声明的属性用的是copy,在合成方法时会使用类的copy方法,所以在此时,即便用的是可变的实例变量,生成的也会是一个不可变的副本,确保了对象不会无意间的被改动

深浅拷贝

对象复制及其中的深浅拷贝的内容在之前已经有所讲解,【oc】Foudation框架–字符串,对象复制详解,但是讲解的有很多当时没有学习的东西所以在这里进行部分补充,这里先展示之前的介绍的相当全面的一张表格:

被拷贝的对象类型拷贝方法是否新容器/新对象是否复制内部元素拷贝类型
非容器类的不可变对象copy否(返回自身)-浅拷贝
非容器类的不可变对象mutableCopy是(新对象)深拷贝
非容器类的可变对象copy是(不可变新对象)是(新对象)深拷贝
非容器类的可变对象mutableCopy是(可变新对象)是(新对象)深拷贝
容器类的不可变对象copy否(返回自身)❌(不复制元素)浅拷贝
容器类的不可变对象mutableCopy是(新容器)❌(不复制元素)深拷贝(容器里元素为浅层)
容器类的可变对象copy是(不可变新容器)❌(不复制元素)深拷贝(容器里元素为浅层)
容器类的可变对象mutableCopy是(新容器)❌(不复制元素)深拷贝(容器里元素为浅层)

先回顾一下浅拷贝本质指的就是创建一个存放与所复制对象的地址相同的指针变量(固也称为指针拷贝),深拷贝指的是创建一个与被复制对象的值完全相同的对象,且他们的地址也不同,所以也叫做内容拷贝

容器类对象的深拷贝

在上面的表格中我们能看出,对容器类进行深拷贝时都只是进行了单层的深拷贝,即只是对容器进行了深拷贝了一份新的内存,但是里面的元素都是浅拷贝,未复制元素本身的内容,于是就有了下面这两种真正的深拷贝

完全深拷贝

对容器本身拷贝一份,且容器里的元素也一一拷贝,使用initWithXxxx: copyItems: YES方法

代码示例:

NSMutableString *str = [NSMutableString stringWithFormat:@"deepcopy"];NSArray *array = @[str];NSArray *arraycopy = [[NSArray alloc] initWithArray: array copyItems: YES];NSLog(@"%p - %p", array[0], arraycopy[0]);NSLog(@"%p - %p", array, arraycopy);

运行结果:

请添加图片描述

但是,当容器里面的元素仍然是容器的时候,我们使用这个方法,在里面的容器的里面的元素仍然是浅拷贝,里面的容器地址是深拷贝后的新地址

代码示例:

NSMutableString *str = [NSMutableString stringWithFormat:@"deepcopy"];NSArray *array = @[str, @[@"nested copy"]];NSArray *arraycopy = [[NSArray alloc] initWithArray: array copyItems: YES];NSLog(@"%p - %p", array, arraycopy);NSLog(@"%p - %p", array[0], arraycopy[0]);NSLog(@"%p - %p", array[1][0], arraycopy[1][0]);

运行结果:

请添加图片描述

显然,里面的容器的里面的元素仍然是浅拷贝,里面容器里的元素的地址仍然是原里面容器的元素的地址,这个时候,就要用到下面的递归深拷贝

递归深拷贝

在容器中嵌套容器时,需要递归的拷贝所有子容器及其内部元素,即要用到归档/解档的方法来进行递归深拷贝,这才是最彻底的深拷贝

代码示例:

NSArray *array01 = @[@[@"1", @"2"], @"3"];//进行安全归档NSData *data = [NSKeyedArchiver archivedDataWithRootObject: array01 requiringSecureCoding: YES error: nil];
//进行安全解档NSArray *array02 = [NSKeyedUnarchiver unarchivedObjectOfClass: [NSArray class] fromData: data error: nil];NSLog(@"%p - %p", array01[0][1], array02[0][1]);

运行结果:

请添加图片描述

总结

这次算是学习了当时没学到的部分属性关键字和深浅拷贝的更全面的内容,以后学到新的还会继续补充


文章转载自:

http://HEPY7Fxf.ryqsq.cn
http://g6DjcqA5.ryqsq.cn
http://wBXd1TUd.ryqsq.cn
http://oXdcAB1b.ryqsq.cn
http://lRy0897N.ryqsq.cn
http://pNzdGT7v.ryqsq.cn
http://OW8qU28p.ryqsq.cn
http://XP4rcKDS.ryqsq.cn
http://CvVxbQKx.ryqsq.cn
http://pwKT00wD.ryqsq.cn
http://l8XN5dMG.ryqsq.cn
http://RxWxPUBM.ryqsq.cn
http://EDOfKh6M.ryqsq.cn
http://1l9YkTuR.ryqsq.cn
http://fJOD9Tkt.ryqsq.cn
http://UW3R3Msv.ryqsq.cn
http://zCNPP3Hh.ryqsq.cn
http://XtTni6ST.ryqsq.cn
http://7GXEFiPa.ryqsq.cn
http://v5mi9ii3.ryqsq.cn
http://yAc8KGiy.ryqsq.cn
http://x9Qz82iZ.ryqsq.cn
http://i1yozrko.ryqsq.cn
http://Pp8Ky7a6.ryqsq.cn
http://lOnx09TG.ryqsq.cn
http://PP6EfHUl.ryqsq.cn
http://tCg5sbNP.ryqsq.cn
http://yPbha9gd.ryqsq.cn
http://tcbv5Sdy.ryqsq.cn
http://tM7BcVjt.ryqsq.cn
http://www.dtcms.com/a/365369.html

相关文章:

  • 3027. 人员站位的方案数 II
  • 前端自动化打包服务器无法安装高版本 Node.js v22 问题解决
  • 高效文本处理:cut、sort、uniq 和 tr 命令详解与实战
  • 巨头撤退,玩家内卷!2025,IoT平台的生死劫与重生路
  • raspberry Pi 4B(树莓派4B)开启VNC服务 主机用VNC连接
  • Radiant Photo 2.1.0.756 +扩展插件 图像AI增强修饰
  • 时间感知认知诊断模型:原理与实施步骤
  • Vite 环境变量与全局变量详解
  • Java 技术支撑 AI 系统落地:从模型部署到安全合规的企业级解决方案(三)
  • 什么是好的系统设计
  • 虚拟机详细图文教程系列14、Linux虚拟机Centos8系统下载安装Python-Pycharm
  • 【QT随笔】巧用事件过滤器(installEventFilter 和 eventFilter 的组合)之 QComboBox 应用
  • 标准化与定制化的平衡艺术:制造企业如何通过灵活配置释放系统价值
  • 嵌入式第四十五天(51单片机相关)
  • TDD测试驱动开发+Python案例解析
  • SkyWalking 支持的告警通知方式(Alarm Hooks)类型
  • 吱吱企业通讯软件以安全为核心,构建高效沟通与协作一体化平台
  • 驱动开发系列69 - GLSL编译器实现 - 符号表的定义
  • 【SQL Server 2022】保姆级SQL Server 详细图文下载安装教程
  • Unity学习----【进阶】Addressables(一)--概述与简单的使用
  • 涉私数据安全与可控匿名化利用机制研究(上)
  • 代码随想录算法训练营第四十三天|LeetCode300. 最长递增子序列,LeetCode674. 最长连续递增序列,LeetCode718. 最长重复子数组
  • 【C语言数组操作:从指针到下标访问】
  • 【微信小程序预览文件】(PDF、DOC、DOCX、XLS、XLSX、PPT、PPTX)
  • 1分钟生成爆款相声对话视频!Coze智能体工作流详细搭建教程,小白也能轻松上手
  • daily notes[9]
  • 【音视频】FMP4 介绍
  • 从 MMLU 到 HumanEval:为什么评估大型语言模型(LLM)的基准至关重要?
  • 策略模式 + 工厂模式
  • 海伯森检测应用案例之--光学板轮廓及瑕疵检测