面试经典-不被忽略的@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 的相关文章

  • TestFlight 提供反馈按钮

    我正在使用 iOS 8 的最新 testflight 版本 我将自己添加为内部测试人员 现在当我使用 testflight 打开应用程序时 我找不到反馈按钮 如果有人有任何线索 请告诉我 您在 Testflight 应用程序中提供反馈 打开
  • 无法验证包:721772200.itmsp

    我写这篇文章是因为我有一个严重的问题 我在cartoonsmart 网站上购买了Commander Cool 游戏 然而 一个严重的问题发生了 iTune Connect 验证无法接受该申请 我尝试从两个不同的开发者帐户发布它 但错误仍然发
  • mgwt - 以编程方式改变方向

    是否可以在 gwt mgwt 应用程序中更改强制执行特定的屏幕方向 可以说我希望用户始终以横向模式使用应用程序 这取决于 是作为phonegap应用程序 而不是在浏览器内部 如果您作为 Web 应用程序运行 则不需要t get any co
  • iOS Safari Mobile 禁用上一个和下一个选择输入

    上周五我发现了关于此问题的类似问题 但似乎无法再次找到它 如果有人能指出我正确的方向 那就太好了 本质上我在一个页面上有多个选择菜单 第一个在加载时填充 第二个在第一个选择时填充 够简单的 但是 在 iOS 设备中 当您点击选择元素时 它会
  • 如何在 Swift 中将文件名与文件扩展名分开?

    给定包中文件的名称 我想将该文件加载到我的 Swift 应用程序中 所以我需要使用这个方法 let soundURL NSBundle mainBundle URLForResource fname withExtension ext 无论
  • 使用 NSString 进行 UTF8 解码

    我是 Objective C 新手 尝试使用以下示例将格式错误的 UTF8 编码 NSString 转换为格式良好的字符串苹果文档 http developer apple com library mac documentation Coc
  • React-native-vision-camera无法访问后面的普通摄像头

    我正在尝试在 iPhone 11 Pro 上使用 普通 相机 我使用反应本机视觉相机 当我运行这段代码时 const devices useCameraDevices const deviceBack devices back consol
  • CALayer边框奇怪问题

    我正在向 CALayer 添加边框 但有一些奇怪的行为 在我应用的边框之后出现模糊边框 参见屏幕截图 这是我的代码 void configureLabel self hidden YES self textAlignment NSTextA
  • ios swift parse:从 3 个类收集数据

    我有这样的结构 User CardSet 带有指向 User objectId 的指针 user 和 col name 带有点 cards 的卡片到 Card Set objectId 和列 name 我想选择所有卡数据 包括当前用户的卡集
  • Swift,以编程方式更改 UICollectionViewCell 和 UILabel(单元格内)的宽度

    我已将单元格 UICollectionViewCell 的宽度设置为等于 UICollectionView 的宽度 并且我尝试对该单元格中包含的 UILabel 执行完全相同的操作 我认为下面的代码准确地解释了我想要实现的目标 所以我在这里
  • 使用未解析的标识符“FlurryAdInterstitial”

    我正在尝试整合Flurry Interstitial Ads使用cocoapods in Swift and Xcode 7 1 1 我正在关注开发人员雅虎网站上的此文档 https developer yahoo com flurry d
  • UIViewControllerAnimatedTransitioning:旋转更改后黑屏片段

    我已经创建了一个视图控制器转换 只要我不更改设备方向 一切都正常 图 1 显示了应有的屏幕 然后我切换到下一个视图控制器 在其中更改方向 现在我回到第一个视图控制器并再次切换方向 然后我得到的结果如图 2 所示 出现黑色边框 请不要介意屏幕
  • iOS 7 上 Safari 浏览器的用户代理

    我只想在带有 Safari 浏览器的 iPhone 和 iPod 中打开我的网站 对于 Chrome Dolphin 等任何其他浏览器 它不应该打开 但目前我从几乎所有设备获得相同的用户代理 对于Safari User Agent Stri
  • ReactiveCocoa 将 SignalProducers 合二为一

    我正在使用 ReactiveCocoa 并且我有几个 SignalProducers let center NSNotificationCenter defaultCenter let signalProducer1 center rac
  • 在实例化对象之前是否可以检查故事板中是否存在标识符?

    在我的代码中我有这一行 但我想知道是否有办法检查是否 一些控制器 在我将它与 一起使用之前就存在实例化ViewControllerWithIdentifier 方法 如果标识符不存在 则应用程序崩溃 如果没有好的方法 这并不是一个大问题 我
  • 使用 MapKit 的地形和卫星视图

    我是 Mapkit View 的新手 当我给出没有目的地的纬度和经度时 我想显示 MapKit中是否可以通过地形 卫星视图来显示地图 有教程链接吗 我看过一些访问 Google 地图 API html 文件 的示例 有必要吗 或者您可以通过
  • 叠加 SKScene 未显示

    我正在尝试将 SKScene 覆盖在 SCNScene 上 当我在模拟器和 iPhone6 上运行我的应用程序时 overlayScene SKScene 按预期显示 但是当我尝试在 iPhone5 上运行它 尝试了 2 个不同的设备 时
  • 是否可以跨 2 个不同的 iOS 应用程序访问数据?

    假设我在 App1 中存储了一些 ID 数据 并希望在同一设备上的 App2 中访问它 平台上可以这样吗 如果没有的话有什么解决方法吗 您可以使用iOS 钥匙扣 http developer apple com library ios do
  • 更改 iOS7 中 UIAlertView 的字体大小

    我想更改alertView中消息文本和标题文本的字体大小 苹果网站上没有任何文档谈到这一点 但苹果在其子类注释中表示 UIAlertView 类旨在按原样使用 请参考以下链接 https developer apple com librar
  • ios - 如何声明静态变量? [复制]

    这个问题在这里已经有答案了 C 中声明的静态变量如下 private const string Host http 80dfgf7c22634nbbfb82339d46 cloudapp net private const string S

随机推荐

  • 前端预览下载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 自动合成