面试经典-不被忽略的@property

2023-11-07

我们都知道@property是用来声明属性的,可以保存类的状态或信息;而与其相关的内容,诸如copy、weak、深拷贝等,经常会在面试的过程中出现;

接下来深入下这些模糊&熟悉的内容,理理顺;

 

内容概要:

1.@property的本质;

2.自动合成 和 动态合成(动态绑定的应用);

3.原子性修饰符atomic 和 nonatomic;

4.atomic修饰的属性是线程安全的吗?

5.weak 和 strong;

6.__weak __strong __block;

7.assing 和 weak的使用;

    7.1 基础数据类型使用weak修饰的问题;

    7.2 对象类型使用assign修饰的问题;

    7.3 堆 和 栈;

    7.4 为什么基础数据类型可以使用assign修饰;

8.栈是线程安全的吗?

    8.1 线程和进程的区别;

9.copy 和 strong的使用;

    9.1 不可变对象使用strong的问题;

    9.2 可变对象使用copy的问题;

10.copy和mutableCopy;

    10.1深拷贝和浅拷贝;

    10.2 自定义对象如何支持copy方法;

 


 

@property = instance ivar + setter + getter:

注意:

    @synthesize的场景是,如果不手动实现setter和getter,那么编译器会自动为你加上,这是在编译期间;

    我们都知道OC通过动态绑定,在运行时将消息及消息的接收者对应起来的(程序未运行时,两者是不会对应的);

    OC使用的@dynamic指令,可以告诉编译器 与属性关联的方法会以动态的方式实现;所谓动态实现,实际就是开发者自己实现,然后在运行时进行关联,就是上图中我们所说的动态合成,而不使用编译器自动生成的setter和getter;

    


 

@property修饰符:


 

atomic非线程安全的解释说明:

    atomic和nonatomic的区别在于,系统自动生成的getter和setter方法不一样;

        如果我们实现自己的getter和setter,那么内存管理和原子性相关的@property修饰符仅仅是提示,写不写都一样;

        atomic修饰的属性,系统生成的getter和setter会保证get/set操作的完整性,不受其他线程的影响;

            一个属性的多个set/get在不同的线程是线程安全,但操作属性的其他方法不一定;

            离开set/get方法之后的其他执行语句更是如此,也就是说atomic并不能保证所在线程的安全;

        atomic让CPU能在别的线程来访这个属性之前,先执行完当前流程;

        nonatomic的话,如果两个线程访问同一个属性,会出现无法预料的结果;

 

    在如下示例的log中:

        我们看到每次打印时getter获取的值都是有效的,也就是说本身get值,并没有受到其他线程的影响而取不出来;

        但一定要注意,原子性只是保证了set和get方法的操作完整性;

        对所在的线程中其他执行语句并没有约束力,所以不是线程安全的;

        (假设存在这种约束力,那么线程a:——a1之后的log,应该是线程b:-b1-a1)

 

上述是atomic非线程安全的一种解释,还可以这样理解:

    假设有一个atomic属性,线程1、2调用setter方法,线程3调用getter方法,在不同的线程中,这三个方法终将以某个顺序一次执行;

    也就是说,一个线程在执行setter/getter方法时,其他线程只能等待;

    但是,如果线程4中调用了release方法,就会有问题,因为release不受setter/getter方法的约束;

    也就是说atomic修饰的属性,读(get)写(set)是安全的,但不是线程安全的;

    因为别的线程还能进行读写之外的操作,这些操作都不会被约束,线程安全需要开发者自己保证;

 


 

weak和strong:

    弱引用和强引用;

        weak修饰的属性,赋值时,不会对赋值的对象retain,引用计数不会+1,所引用的对象=nil时,该属性还会自动置为nil;

        strong修饰的属性,赋值时,会对赋值的对象retain,引用计数会+1,strong是默认的缺省修饰符;

    二者的根本区别是在set方法中,虽然来两者的set方法都是对旧对象release释放,对新对象retain保留,但

        weak的set方法在retain之后会进行一次autorelease,而strong不会,最终效果就是strong引用计数会+1,weak则不会;

    主要用于解决循环引用;

 

__weak 和 __strong关联的变量修饰符(引用类型):

    在调用block的时候是采用copy方式,这是因为一般生成的block都是在栈上,通过copy之后的block会在堆上,相应的引用计数也会增加;

    copy到堆上时,block的外部变量也会被copy,对象类型的引用变量的引用计数会+1,如果这个对象对block持有,block中又使用了(捕获)这个对象,就会造成循环引用,这会导致对象无法释放;

    此时只需要在block外部重新定义一个采用__weak修饰的变量,这个变量指向object,然后在block中使用此变量即可;

 

    虽然使用了__weak解决了循环引用的问题,但是这个变量也有可能随时被释放掉,为了能够使用该对象,可以在block内部一开始的地方定义一个__strong的变量,这个__strong变量指向外部定义的__weak变量;

 

使用方式:

    这保证了整个block中对象一直被强引用而不被释放;

__weak typeof(self) wself = self;

>block{

    __strong typeof(wself) sself = wself;

}

 

__block存储类型修饰符(值类型):

    如果需要在block中修改外部的变量值,这个变量可以是静态变量、静态全局变量,全局变量;

        原因是:全局变量 是存储在全局区,静态变量传递给Block的内存地址;

    还有一种方式是对自动变量的:

        自动变量的值,被copy进了Block,不带__block的自动变量只能在里边被访问,并不能改变值;

        带__block的自动变量和静态变量就是直接地址访问,这么说不太严格:自动变量和静态变量还不一样,这里静态变量指的是静态局部变量,他确实是在block底层的结构体上存储了变量的指针,而使用__block修饰的自动变量,则是生成了一个新的结构体,保存了自动变量的地址和值,block结构体实际保存的是这个新的结构体指针,所以Block里可以直接改变便来能的值;

    带有__block修饰符的变量会被捕获到Block内部持有;

 


 

我们介绍了使用assign修饰的属性,在对象释放之后,变成野指针,带来崩溃,那为什么基本数据类型可以使用assign修饰呢?

 

我们深入堆栈来看下:

 

使用assign修饰的基本数据类型之所以没有野指针,是因为:

    基本数据类型是分配在栈上,栈空间的分配和回收是由系统管理的,也就不会产生野指针的问题了;

 


 

栈是线程安全的吗?

我们先来回顾一下进程和线程;

 

进程和线程的关系:

    线程是进程的实体,是CPU调度和分派的基本单位;

        一个进程可以有多个线程,线程本身只有很少的,运行时必要的资源,不分配系统资源;

    线程与同一进程的其他线程共享进程资源;

        一个进程中的所有线程共享该进程的地址空间,但是每个线程有自己独立的栈,堆则是进程独有的,为进程中其他线程共享;

 

所以栈 是 线程安全的:

    栈是每个线程独有,保存线程的运行状态和局部变量;会在线程开始的时候分配;

    堆是多个线程所共有的空间,操作系统在对进程进行初始化的时候,对堆进行分配;

 


 

@property修饰符的进一步说明:copy、string、mutableCopy

 

copy和strong:

    @property (nonatomic , copy) NSString *sex;

    @property (nonatomic , strong) NSMutableArray * books;

通常:

    不可变对象属性修饰符使用copy;

    可变对象属性修饰符使用strong;

 

可变对象和不可变对象:

    不可变对象,如NSArray,NSString等;(改变变量的值,指针的地址会重新分配赋值)

    可变对象,如NSMutableArray,NSMutableString等;(改变变量的值,指针的地址不变)

 

不可变对象使用strong的问题:

    我们使用了strong修饰了strongStr属性,这是一个NSString类型,很明显我们需要的是一个不可变对象;

    依照如下示例,我们会发现,虽然打印的两个变量的地址一致,但是地址在没有改变的情况下,不可变对象属性的值被篡改了;

 

可变对象使用copy的问题:

    我们使用copy修饰了mutiStr属性,这是一个NSMutableString类型,很明显我们需要的是一个可变类型的对象;

    依照如下示例,我们发现,程序报错,原因在于mutiStr属性实际是NSString类型,没有appendString方法;

 

我们来分析下copy修饰的可变对象属性赋值时到底发生了什么:

    self.mutiStr = [NSMutableString stringWithString:tempStr];

    <=>

    NSMutableString tempString = [NSMutableString stringWithString: tempStr];

    self.mutiStr = [tempString copy];

    这里要注意,通过copy方法得到的对象是一个不可变的对象(使用mutableCopy方法返回的才是可变对象),自然没有可变对象的方法;

 


 

copy和mutableCopy:

    二者的差异主要和深拷贝和浅拷贝有关;

 

深拷贝和浅拷贝:

    浅拷贝:引用计数+1,并没有申请新的内存区域,只是另一个指针指向了该区域;

    深拷贝:申请新的内存区域,与原内存区域中的内容是一样的,原内存区域的引用计数不变;

 

可变对象的copy和mutableCopy:

    可变对象的copy和mutableCopy都是深拷贝,只不过方法返回的对象类型不同;

    

不可变对象的copy和mutableCopy:

    不可变对象的copy是浅拷贝;

    mutableCopy是深拷贝;    

 


 

自定义对象如何支持copy方法:

    自定义对象支持copy方法,只需要支持NSCopying协议,且实现copyWithZone方法;

    对于当前对象的可变对象属性,需要使用mutableCopyWithZone操作;

 


 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

面试经典-不被忽略的@property 的相关文章

  • Xcode 8 - 删除了一些按钮边框

    我刚刚将 Xcode 版本从 7 3 更新到 8 0 一些按钮边框消失了 代码看起来很好 所以我真的不知道各层发生了什么 顺便说一句 在其他一些控制器中我可以看到图层边框 self button layer borderColor bord
  • 检测iOS设备类型

    在我的应用程序 用 Objective C 编写 中 如何检测设备是 iPhone iPad 还是 iPhone5 if UIDevice currentDevice userInterfaceIdiom UIUserInterfaceId
  • AVAssetWriter 如何编写下采样/压缩的 m4a/mp3 文件

    我正在尝试获取本地 m4a 或 mp3 文件并压缩 下采样该文件 为了制作更小的文件 最初 我使用 AVAssetExportSession 将 AVAsset 导出到临时目录 但我对压缩 下采样没有任何控制 您只能使用预设 其中只有 wa
  • iCarousel 滚动不顺畅

    我正在使用 iCarousel 滚动标签 在模拟器上一切正常 但在 iPad iPhone 上滚动不顺畅和快速 这是代码 城市列表视图 h import
  • UISearchBar 在单击时修改其框架/边界

    我正在尝试将 UISearchController 放置在我的应用程序 UI 中 布局是 黄色 ViewController 红色 另一个 ViewController 黑色 YellowViewController 中的容器 我想将 UI
  • UITableview Commit EditingStyle 具有多个按钮? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 如何在 UITableview 提交编辑样式中添加多个按钮 我需要显示一个带有删除按钮的更多按钮 由于无法使用公共API 所以你可以更好地
  • RestKit:BOOL 值

    我有一个NS ENUM保存清单的状态 这两个属性是Pending and Completed typedef NS ENUM NSUInteger ChecklistStatus Pending Completed 我正在尝试获取状态并将其
  • 如何在应用程序打开或关闭的情况下在后台的特定日期时间快速运行任务

    我正在开发闹钟应用程序 我需要在特定时间安排闹钟 我使用scheduleLocalNotification用于安排警报 它工作正常 如我所愿 BUT在触发警报之前 我需要向 API 服务器发出请求 在该请求中 我想检查从 API 服务器返回
  • 当我编写 FirebaseApp.configure() 时,iOS 应用程序崩溃

    我有一个 ios 应用程序 可以正常登录和 Facebook 登录 今天我集成了 firebase 当我在应用程序委托中编写 FirebaseApp configure 时 我的应用程序崩溃了 并且此函数突出显示错误代码 在展开可选值时意外
  • Vimeo 播放器 JS API 在 iOS 中无法运行

    我正在尝试使用 API 来播放视频 但只有在 iOS 中单击播放器中的播放按钮后它才有效 在桌面版和 Android 版 Chrome 中 它运行良好 http codepen io bdougherty pen JgDfm http co
  • Google 地图 ios:Mapview 路线垂直折线始终指向位置箭头的北部或顶部

    我已经在我的应用程序中实现了 Google Maps IOS 的基本功能 我必须将地图视图的方位设置为始终指向顶部或北部 我需要 如果我点击导航按钮 地图视图应该动画到位置箭头顶部 就像谷歌地图 ios 应用程序一样 箭头应始终固定并指向北
  • 保护移动连接 - 存储秘密和密钥

    感谢您花时间阅读本文 我是一名年轻的开发人员 在 Web 项目和服务器端编码方面拥有一些专业经验 但我现在正在构建我的第一个移动应用程序 经过在线深入研究后 我还没有能够澄清我关于保护移动应用程序数据传输的一些问题 这是我认为我理解正确的
  • Xcode 11 向后兼容性:“UIWindowScene 仅在 iOS 13 或更高版本中可用”

    在 Xcode 11 中 我从 Single View App 模板创建了一个新的应用程序项目 我希望这个应用程序能够在 iOS 12 和 iOS 13 中运行 但是当我将部署目标切换到 iOS 12 时 我收到了很多类似这样的错误消息 U
  • kCVPixelFormatType_420YpCbCr8BiPlanarFullRange 帧到 UIImage 转换

    我有一个应用程序可以捕获 kCVPixelFormatType 420YpCbCr8BiPlanarFullRange 格式的实时视频来处理 Y 通道 根据苹果的文档 kCVPixelFormatType 420YpCbCr8BiPlana
  • 如何加密捆绑的文本/json 文件?

    我的 iOS 应用程序捆绑了几个文件 现在 如果有人下载该应用程序并访问 ipa 文件 他就可以轻松阅读它们 我想让事情变得更难 您知道有关该主题的任何资源吗 我想我需要一个加密库 以及编码文件的构建脚本中的一些脚本 当然 我知道有人可能会
  • 检查url图片是否存在

    我正在尝试使用 if 语句检查 url 图像是否存在 然而 当尝试通过错误的图像网址测试它时 它会不断返回 致命错误 在解包可选值时意外发现 nil code var httpUrl subJson image url stringValu
  • 如何在 iPhone 上缩小 UIPickerView?

    我想降低一个高度UIPickerView在我的 iPhone 应用程序中 使其仅显示一行和一列 选择器视图的高度应等于行的高度 我正在使用 Interface Builder 来构建UIPickerView 但我找不到调整此控件大小的简单方
  • Siri - 联系人搜索行为类似于 Skype 的音频通话

    我正在实现一个 VoIP 应用程序 我需要通过 Siri 发起呼叫 我能够通过 Siri 发起呼叫 但问题是 每次启动应用程序时 尽管联系人不在应用程序的联系人列表中 我不知道如何以及在哪里处理这个问题 我的意思是 如果应用程序没有像 Sk
  • UICollectionViewFlowLayout IOS的​​minimumLineSpacing属性

    对于UICollectionViewFlowLayout的属性minimumLineSpacing 苹果的文档说 对于垂直滚动网格 该值表示最小值 连续行之间的间距 对于水平滚动的网格 该值表示连续列之间的最小间距 我测试它和代码的一部分是
  • 如何使用 Swift 将文本复制到剪贴板/粘贴板

    我正在寻找一个干净的示例 说明如何将文本复制到 iOS 剪贴板 然后可以在其他应用程序中使用 粘贴 该功能的好处是可以快速复制文本 无需传统文本复制的标准文本突出显示功能 我假设关键课程位于UIPasteboard 但在中找不到相关区域他们

随机推荐

  • 前端预览下载pdf文件

    合同预览 拿到需要合同显示的数据 后台需要的参数 将参数经过base64编码传给后台 后段规定 问题 base64可能会将某些字符串符号编译为空格 后台返回一个文件地址 创建a标签 href指向返回的文件地址 function viewCo
  • Lecture13_光线追踪1(Whitted-Style Ray Tracing)_GAMES101 课堂笔记

    引入光线追踪目的 因为光栅化不能很好地处理全局效果 例如 软阴影 光栅化需要经过两个过程才能形成软阴影 Glossy 反射 既有反射 又有本身材质的粗糙性影响 间接反射 光线在空间中会反射很多次 很难渲染 光栅化速度快 但是质量并不好 表现
  • 如何重新启动k8s集群,并查看的状态

    重新启动k8s集群的方法取决于您使用的部署方式 如果您使用的是kubeadm部署 可以使用以下命令重启集群 kubeadm reset kubeadminit 如果您使用的是其他部署工具 请按照该工具的说明操作 查看集群状态可以使用kube
  • C#显式实现接口函数

    如果一个类实现了一个接口 他可以选择显示实现这个接口 如果显示实现了接口的话 要调用接口的方法 就必须将类型转换为接口去调用 如果要使用类的实例去调用 就必须为类实现该接口函数 例如 interface IShowMessage void
  • Vue3:Typescript与组合式API、defineProps、defineEmits等使用

    标注类型 props 使用 defineProps 使用
  • 【SQL Server 2016】&【SSMS 17】安装

    一 SQL Server 2016安装 1 1 光盘映像下载 SQL Server Downloads 1 2 安装光盘映像 首次安装点击 全新SQL Server独立安装或向现有安装添加功能 产品密钥自动输入 下一步 勾选 我接受许可条款
  • 解决yolov7bug(Command ‘git tag‘ returned non-zero exit status 128.)(IndexError: list index out of ran)

    1 问题 执行train py Command git tag returned non zero exit status 128 原因 使用预训练权重 但路径错误 未找到本地预训练权重 它会自动下载 下载被墙 解决方法 从github下载
  • 透视投影详解

    透视投影详解 概述 投影变换完成的是如何将三维模型显示到二维视口上 这是一个三维到二维的过程 你可以将投影变换看作是调整照相机的焦距 它模拟了为照相机选择镜头的过程 投影变换是所有变换中最复杂的一个 视锥体 视锥体是一个三维体 他的位置和摄
  • electron 获取电脑mac地址遇到的坑

    最近公司需求做一个exe程序 无奈只是一个小前端 只能使用electron来实现了 其中一个需求就是每个账号绑定唯一的电脑 这里选用网卡的mac地址来做这个唯一的字段 代码很简单 测试也很顺利 const mainWindow new Br
  • 房地产投资占GDP比例畸高 中国房地产泡沫是一颗毒瘤

    转 http house ifeng com detail 2014 05 04 46139202 0 shtml 房地产投资占GDP比例畸高 2013年房地产投资占GDP比例高达16 而事实上从1960年来但凡房地产投资占GDP比例高于6
  • 昇思MindSpore安装教程

    目录 昇思MindSpore安装教程 MindSpore 安装MindSpore 开始安装 创建虚拟环境 进入工作目录 下载完成 验证是否成功安装 关注MindSpore社区官方号 昇思MindSpore安装教程 MindSpore 它是华
  • [js] : js 设置 style 的 important

    const div document getElementById xxx div style setProperty height 100px important api 详情 参见 CSSStyleDeclaration getProp
  • 论文笔记:Blockchain in Industries: A Survey

    一 基本信息 论文题目 Blockchain in Industries A Survey 发表时间 IEEE Access 2019 作者及单位 二 摘要 区块链技术近来已成为研究和工业界的最前沿 因为它们为许多行业带来了潜在的好处 这是
  • 02_Numpy学习笔记(下):随机采样

    02 Numpy学习笔记 下 随机采样 文章目录 02 Numpy学习笔记 下 随机采样 一 离散型随机变量的分布 1 二项分布 2 泊松分布 3 超几何分布 二 连续型随机变量的分布 1 均匀分布 2 正态分布 3 指数分布 三 其他随机
  • 华为OD机试真题 Java 实现【日志采集系统】【2023Q1 100分】,附详细解题思路

    目录 一 题目描述 二 输入描述 三 输出描述 四 解题思路 五 Java算法源码 六 效果展示 1 输入 2 输出 3 说明 一 题目描述 日志采集是运维系统的的核心组件 日志是按行生成 每行记做一条 由采集系统分批上报 如果上报太频繁
  • Python装饰器探究

    说在前边 装饰器作为Python中的一个比较实用的东西 在我们日常库的使用过程中经常使用 但是其细节问题我们却常常忘记考虑 本文章就此问题写建装饰器代码来进行一步一步分析 装饰器实验 1 我们常见的装饰器使用方式 from functool
  • ROS激光SLAM导航理解

    ROS激光SLAM导航理解 注 最近学习ROS的激光导航知识 需要理清ROS的SLAM 环境感知 costmap 与导航算法 为防止自己忘记 将觉得有价值的内容收集于此 对AGV来说 SLAM是个大大坑 环境感知和局部运动控制也是大坑 学习
  • 数据库添加/删除/修改 表字段(超详细)

    Oracle 添加 删除 修改 表字段 超详细 1 添加表字段 1 1 语法结构 1 2 举例说明 1 新建学生信息表 该步骤可忽略 2 初始表样子 3 语法解释 2 修改表字段 2 1 语法结构 1 修改字段属性 2 修改字段名 2 2
  • games101课程作业,在Vs2019环境下的配置环境(不使用虚拟机)

    为什么不使用虚拟机 因为虚拟机使用ubuntu x64版本系统 是一个从未接触过的系统 不好使用 虚拟机中无法使用中文输入法 无法对代码进行注释 不利于学习 虚拟机性能差 打开两三个文件就卡 令人抓狂 要使用终端进行编译 很是麻烦 还是喜欢
  • 面试经典-不被忽略的@property

    我们都知道 property是用来声明属性的 可以保存类的状态或信息 而与其相关的内容 诸如copy weak 深拷贝等 经常会在面试的过程中出现 接下来深入下这些模糊 熟悉的内容 理理顺 内容概要 1 property的本质 2 自动合成