iOS面试之属性关键字(二):常见面试题
Q:ARC下,不显式指定任何属性关键字时,默认的关键字都有哪些?
对应基本数据类型默认关键字是:atomic,readwrite,assign
对于普通的 Objective-C 对象:atomic,readwrite,strong
Q:atomic 修饰的属性是怎么样保存线程安全的?
答:编译器会自动生成互斥锁,对 setter 和 getter 方法进行加锁,可以保证属性的赋值和取值原子性操作是线程安全的,但不包括操作和访问。
比如说atomic修饰的是一个数组的话,那么我们对数组进行赋值和取值是可以保证线程安全的。但是如果我们对数组进行操作,比如说给数组添加对象或者移除对象,是不在atomic的负责范围之内的,所以给被atomic修饰的数组添加对象或者移除对象是没办法保证线程安全的。
Q:什么情况使用 weak 关键字,相比 assign 有什么不同?
答:
在 ARC 中,在有可能出现循环引用的时候,往往要通过让其中一端使用 weak 来解决,比如: delegate、block。
自身已经对它进行一次强引用,没有必要再强引用一次,此时也会使用 weak,自定义 IBOutlet 控件属性一般也使用 weak,使用 storyboard(xib 不行)创建的 vc,会有一个叫 _topLevelObjectsToKeepAliveFromStoryboard 的私有数组强引用所有 top level 的对象,所以这时即便 outlet 声明成 weak 也没关系。当然,也可以使用 strong。
weak 和 assign 的不同点:
① weak只能修饰对象,而assign既可以修饰对象也可以修饰基本数据类型;
② assign修饰的对象在被释放后,指针仍然指向原对象地址;而weak修饰的对象在被释放之后会自动置指针为 nil;
③ 相同点:在修饰对象的时候,assign和weak都不改变对象的引用计数。
Q:weak修饰的释放则自动被置为nil的实现原理
答:weak 实现原理的概括:
Runtime维护了一个weak表,用于存储指向某个对象的所有weak指针。weak表其实是一个hash(哈希)表,Key是所指对象的地址,Value是weak指针的地址(这个地址的值是所指对象的地址)数组。
weak 的实现原理可以概括一下三步:
1、初始化时:runtime会调用objc_initWeak函数,初始化一个新的weak指针指向对象的地址。
2、添加引用时:objc_initWeak函数会调用 objc_storeWeak() 函数, objc_storeWeak() 的作用是更新指针指向,创建对应的弱引用表。
3、释放时,调用clearDeallocating函数。clearDeallocating函数首先根据对象地址获取所有weak指针地址的数组,然后遍历这个数组把其中的数据设为nil,最后把这个entry从weak表中删除,最后清理对象的记录。
Q:为什么iOS开发中,控件一般为weak而不是strong?
IBOutlet的属性一般可以设为weak是因为它已经被view引用了,除非view被释放,否则IBOutlet的属性也不会被释放,另外IBOutlet属性的生命周期和view应该是一致的,所以IBOutlet属性一般设为weak。
简单的说,如果IBOutlet对象是nib/xib scene的拥有者(File’s owner)所持有的对象,那么很显然拥有者必须“拥有”对象的指针,因此属性应设置为strong。而其他的IBOutlet对象的属性需要设置为weak,因为拥有者并不需要“拥有”他们的指针。
答:因为view被添加到superView上面后,就被superView持有了。我们一般在IB里面的拖的view都是加在了根view或者它的子view上。而根view又被它的controller持有,所以IBOutlet可以用weak。如果,在IB里面拖出来的view是一个单独的view没有被加到任何其他view上,则需要用strong。
Q:以下代码会出现什么问题?(深浅拷贝)
@property (copy) NSMutableArray *array;
答:
1.把NSMutableArray用copy修饰有时就会crash,因为对这个数组进行了增删改操作,而copy后的数组变成了不可变数组NSArray,没有响应的增删改方法,所以对其进行增删改操作就会报错。
2.默认atomic修饰,编译器会自动生成互斥锁,对 setter 和 getter 方法进行加锁操作,这个过程会消耗一些性能,执行效率慢,一般使用nonatomic修饰
Q:用@property声明的NSString(或NSArray,NSDictionary)经常使用copy关键字,为什么?如果改用strong关键字,可能造成什么问题?
1.因为父类指针可以指向子类对象,使用 copy 的目的是为了让本对象的属性不受外界影响,使用 copy 无论给我传入是一个可变对象还是不可对象,我本身持有的就是一个不可变的副本.
2.如果我们使用是 strong ,那么这个属性就有可能指向一个可变对象,如果这个可变对象在外部被修改了,那么会影响该属性.
copy 此特质所表达的所属关系与 strong 类似。然而设置方法并不保留新值,而是将其“拷贝” (copy)。
Q:@property 的本质是什么?ivar、getter、setter 是如何生成并添加到这个类中的?
@property的本质是 ivar(实例变量) + getter + setter.
attributes的具体内容包含: 类型, 原子性, 内存语义和对应的实例变量.
我们每次在增加一个属性, 系统都会在 ivar_list 中添加一个成员变量的描述, 在 method_list 中增加 setter 与 getter 方法的描述, 在属性列表中增加一个属性的描述, 然后计算该属性在对象中的偏移量, 然后给出 setter 与 getter 方法对应的实现, 在 setter 方法中从偏移量的位置开始赋值, 在 getter 方法中从偏移量开始取值, 为了能够读取正确字节数, 系统对象偏移量的指针类型进行了类型强转.
Q:weak属性需要在dealloc中置nil么?
不需要。
在ARC环境无论是强指针还是弱指针都无需在 dealloc 设置为 nil , ARC 会自动帮我们处理
即便是编译器不帮我们做这些,weak也不需要在 dealloc 中置nil:因为在属性所指的对象遭到摧毁时,属性值也会清空(nil out)。
当一个被weak修饰的对象被释放后,weak对象怎么处理的?
清除weak变量,同时设置指向为nil。当对象被dealloc释放后,在dealloc的内部实现中,会调用弱引用清除的相关函数,会根据当前对象指针查找弱引用表,找到当前对象所对应的弱引用数组,将数组中的所有弱引用指针都置为nil。
Q:说说你理解weak属性?
Runtime维护了一个weak表,用于存储指向某个对象的所有weak指针。weak表其实是一个hash(哈希)表,Key是所指对象的地址,Value是weak指针的地址(这个地址的值是所指对象的地址)数组。
1、初始化时:runtime会调用objc_initWeak函数,初始化一个新的weak指针指向对象的地址。
2、添加引用时:objc_initWeak函数会调用 objc_storeWeak() 函数, objc_storeWeak() 的作用是更新指针指向,创建对应的弱引用表。
3、释放时,调用clearDeallocating函数。clearDeallocating函数首先根据对象地址获取所有weak指针地址的数组,然后遍历这个数组把其中的数据设为nil,最后把这个entry从weak表中删除,最后清理对象的记录。
追问的问题一:
1.实现weak后,为什么对象释放后会自动为nil?
runtime 对注册的类, 会进行布局,对于 weak 对象会放入一个 hash 表中。 用 weak 指向的对象内存地址作为 key,当此对象的引用计数为 0 的时候会 dealloc,假如 weak 指向的对象内存地址是 a ,那么就会以 a 为键, 在这个 weak 表中搜索,找到所有以 a 为键的 weak 对象,从而设置为 nil 。
追问的问题二:
2.当weak引用指向的对象被释放时,又是如何去处理weak指针的呢?
1、调用objc_release
2、因为对象的引用计数为0,所以执行dealloc
3、在dealloc中,调用了_objc_rootDealloc函数
4、在_objc_rootDealloc中,调用了object_dispose函数
5、调用objc_destructInstance
6、最后调用objc_clear_deallocating,详细过程如下:
a. 从weak表中获取废弃对象的地址为键值的记录
b. 将包含在记录中的所有附有 weak修饰符变量的地址,赋值为 nil
c. 将weak表中该记录删除
d. 从引用计数表中删除废弃对象的地址为键值的记录
10.iOS本地数据存储安全
11.BAD_ACCESS的错误吗?你是怎样调试的?
BAD_ACCESS:不管什么时候当你遇到BAD_ACCESS这个错误,那就意味着你向一个已经释放的对象发送消息。
BAD_ACCESS的本质:
在C和OC中,你一直在处理指针,指针无非是存储另一个变量的内存地址的变量。当向一个对象发送消息时,指向该对象的指针将会被引用,这意味着,你获取了指针所指的内存地址,并访问该存储区域的值。
当该存储器区域不再映射到你的应用时,或者换句话说,该内存区域在你认为使用的时候没有使用,该内存区域是无法访问的,这时内核会抛出一个异常(EXC),表明你的应用程序不能访问该存储器区域(BAD_ACCESS).
当你碰到BAD_ACCESS,这意味着你试图发送消息到的内存块,但内存块无法执行该消息。但是,在某些情况下,BAD_ACCESS是由被损坏的指针引起的,每当你的应用程序尝试引用损坏的指针,一个异常就会被内核抛出。
Q:@synthesize和@dynamic分别有什么作用?
1.@property有两个对应的词,一个是 @synthesize,一个是 @dynamic。如果 @synthesize和 @dynamic都没写,那么默认的就是@syntheszie var = _var;
2.@synthesize 的语义是如果你没有手动实现 setter 方法和 getter 方法,那么编译器会自动为你加上这两个方法。
3.@dynamic 告诉编译器:属性的 setter 与 getter 方法由用户自己实现,不自动生成。(当然对于 readonly 的属性只需提供 getter 即可)。假如一个属性被声明为 @dynamic var,然后你没有提供 @setter方法和 @getter 方法,编译的时候没问题,但是当程序运行到 instance.var = someVar,由于缺 setter 方法会导致程序崩溃;或者当运行到 someVar = var 时,由于缺 getter 方法同样会导致崩溃。
///
@property有两个关键词, @synthesize(默认值)和@dynamic.
@synthesize表示系统会默认添加一个@syntheszie var = _var的实例变量, 并且自动生成setter和getter方法. @synthesize 合成实例变量有以下几点规则:
如果指定了成员变量的名称, 会生成一个指定的名称的成员变量.
如果这个成员已经存在就不再生成了.
如果没有指定成员变量的名称会自动生成一个属性同名的成员变量.
@synthesize的使用场景:
同时重写了setter和getter时
重写了只读属性的getter时
在使用了@dynamic时
在@Protocol和category中定义属性时
重载父类的属性时, 来手动合成Ivar(实例变量/成员变量).
@dynamic表示我们不需要系统自动生成, 由用户自己实现, 如果没有手动生成的话, 在使用过程中是会奔溃的.
Q:@synthesize合成实例变量的规则是什么?假如property名为foo,存在一个名为_foo的实例变量,那么还会自动合成新变量么?
总结下 @synthesize 合成实例变量的规则,有以下几点:
如果指定了成员变量的名称,会生成一个指定的名称的成员变量,
如果这个成员已经存在了就不再生成了.
如果是 @synthesize foo; 还会生成一个名称为foo的成员变量,也就是说:
如果没有指定成员变量的名称会自动生成一个属性同名的成员变量,
如果是 @synthesize foo = _foo; 就不会生成成员变量了.
假如 property 名为 foo,存在一个名为 _foo 的实例变量,那么还会自动合成新变量么?
不会。
Q:在有了自动合成属性实例变量之后,@synthesize还有哪些使用场景?
什么情况下不会autosynthesis(自动合成)?
同时重写了 setter 和 getter 时
重写了只读属性的 getter 时
使用了 @dynamic 时
在 @protocol 中定义的所有属性
在 category 中定义的所有属性
重载的属性
当你在子类中重载了父类中的属性,你必须 使用 @synthesize 来手动合成ivar。
@synthesize 语法还有一个应用场景,但是不太建议大家使用:
可以在类的实现代码里通过 @synthesize 语法来指定实例变量的名字
@implementation CYLPerson
@synthesize firstName = _myFirstName;
@synthesize lastName = _myLastName;
@end
可变数组&不可变数组修饰符的使用结论:
当修饰可变类型的属性时,如NSMutableArray、NSMutableDictionary、NSMutableString,用strong。
当修饰不可变类型的属性时,如NSArray、NSDictionary、NSString,用copy。
深拷贝与浅拷贝
浅拷贝就是拷贝之后,并没有真正的复制,而是复制对象和原对象都指向同一个地址
深拷贝是真正的复制了一份,复制的对象只想新的地址;
copy:对于可变对象为深拷贝,对于不可变对象为浅拷贝;
mutablecopy:始终为深拷贝;
浅拷贝简单点说就是对内存地址的复制,让目标对象指针和源对象指针指向同一片内存空间;
深拷贝: 内容拷贝,会创建一个新的对象。深拷贝就是拷贝地址中的内容,让目标对象产生新的内存区域,且将源内存区域中的内容复制到目标内存区域中;
Q:objc中的类方法和实例方法有什么本质区别和联系?
(实例变量 = 成员变量 = ivar)
类方法:
1. 类方法是属于类对象的
2. 类方法只能通过类对象调用
3. 类方法中的self是类对象
4. 类方法可以调用其他的类方法
5. 类方法中不能访问成员变量
6. 类方法中不定直接调用对象方法
实例方法:
1. 实例方法是属于实例对象的
2. 实例方法只能通过实例对象调用
3. 实例方法中的self是实例对象
4. 实例方法中可以访问成员变量
5. 实例方法中直接调用实例方法
6. 实例方法中也可以调用类方法(通过类名)
相关文章:

iOS面试之属性关键字(二):常见面试题
Q:ARC下,不显式指定任何属性关键字时,默认的关键字都有哪些? 对应基本数据类型默认关键字是:atomic,readwrite,assign 对于普通的 Objective-C 对象:atomic,readwrite,strong Q:atomic 修饰的属性是怎么样保存线程安全的&#x…...

java开发设计模式详解
目录 一、概述 1. 创建型模式(5种) 2. 结构型模式(7种) 3. 行为型模式(11种) 二、代码示例说明 1.单例模式(Singleton) 2.工厂方法模式(Factory Method) 3.抽象工厂模式(Abstract Factory) 4.建造者模式(Builder) 5.原型模式 (Prototype) 6.适…...

windows中node版本的切换(nvm管理工具),解决项目兼容问题 node版本管理、国内npm源镜像切换(保姆级教程,值得收藏)
前言 在工作中,我们可能同时在进行2个或者多个不同的项目开发,每个项目的需求不同,进而不同项目必须依赖不同版本的NodeJS运行环境,这种情况下,对于维护多个版本的node将会是一件非常麻烦的事情,nvm就是为…...

测试面试宝典(四十四)—— APP测试和web测试有什么区别?
一、系统架构和运行环境 APP 测试需要考虑不同的操作系统(如 iOS、Android 等)、设备型号和屏幕尺寸,以及各种网络连接状态(如 2G、3G、4G、WiFi 等)。而 Web 测试主要针对不同的浏览器(如 Chrome、Firefo…...

力扣高频SQL 50题(基础版)第三十七题
文章目录 力扣高频SQL 50题(基础版)第三十七题176.第二高的薪水题目说明实现过程准备数据实现方式结果截图总结 力扣高频SQL 50题(基础版)第三十七题 176.第二高的薪水 题目说明 Employee 表: ----------------- …...

web基础之CSS
web基础之CSS 文章目录 web基础之CSS一、CSS简介二、基本用法2、CSS应用方式2.1 行内样式2.2内部样式2.3外部样式 三、选择器1、标签选择器2、类选择器3、ID选择器4、选择器的优先级 四、常见的CSS属性1、字体属性2、文本属性3、背景属性4、表格属性5、盒子模型的属性6、定位 总…...

全球轻型卡车胎市场规划预测:2030年市场规模将接近1153亿元,未来六年CAGR为2.0%
一、引言 随着全球物流行业的持续发展,轻型卡车胎作为物流运输的关键消耗品,其市场重要性日益凸显。本文旨在探索轻型卡车胎行业的发展趋势、潜在商机及其未来展望。 二、市场趋势 全球轻型卡车胎市场的增长主要受全球物流行业增加、消费者对轮胎性能要…...

8.2 数据结构王道复习 2.3.3 2.3.7选择题错题review
王道中这章主讲了线性表的定义、基本操作、顺序表示、链式表示。下方内容主分了文字部分和代码部分,便于记忆和整理。 在901中这章的要求集中在链表的基础操作中,应用题大概会出问答题。 【当前每一小节的应用题待做,先把选择题过完ÿ…...

【DL】神经网络与机器学习基础知识介绍(二)【附程序】
原文:https://mengwoods.github.io/post/dl/009-dl-fundamental-2/ 文章目录 激活函数卷积神经网络超参数其他程序 激活函数 激活函数的目的是在模型中引入非线性,使网络能够学习和表示数据中的复杂模式。列出常见的激活函数。 线性函数: y…...

6万字嵌入式最全八股文面试题大全及参考答案(持续更新)
目录 冒泡排序算法的平均时间复杂度和最坏时间复杂度分别是多少?在什么情况下使用冒泡排序较为合适? 选择排序算法是稳定的排序算法吗?为什么? 插入排序在近乎有序的数组中表现如何?为什么? 快速排序的基本思想是什么?它在最坏情况下的时间复杂度是多少? 归并排序…...

iceberg 用户文档(持续更新)
iceberg 用户文档 表 Schema 变更查看表的元数据信息表参数变更 表 Schema 变更 Iceberg 支持使用 Alter table … alter column 语法对 Schema 进行变更,示例如下 -- spark sql -- 更改字段类型 ALTER TABLE prod.db.sample ALTER COLUMN measurement TYPE doubl…...

基于YOLOv8的船舶检测系统
基于YOLOv8的船舶检测系统 (价格85) 包含 【散货船,集装箱船,渔船,杂货船,矿砂船,客船】 6个类 通过PYQT构建UI界面,包含图片检测,视频检测,摄像头实时检测。 (该…...

使用腾讯云域名解析实现网站重定向
前言 最近,在CSDN平台上我写了一系列博客,希望能与同学分享一些技术心得。然而,每当需要向他人推荐我的博客时,那串复杂且缺乏规律的CSDN博客首页域名总让我感到不便。这让我开始思考,如果能将这一域名替换为一个既个…...

为什么相比直接使用new和std::shared_ptr构造函数,make_shared在内存分配和管理方面更为高效。
使用std::make_shared相比于直接使用new和std::shared_ptr构造函数在内存分配和管理方面更为高效,主要原因如下: 内存分配效率 std::make_shared通过一次内存分配来同时分配控制块(用于引用计数等)和对象的内存。这种方式减少了…...

7-Python数据类型——列表和元组的详解(增删改查、索引、切片、步长、循环)
一、列表 1.1 列表 list 有序且可变的容器,可以存放多个不同类型的元素 列表就是专门用来记录多个同种属性的值 列表:存储同一个类别的数据,方便操作 字符串,不可变:即:创建好之后内部就无法修改【内置…...

大数据-61 Kafka 高级特性 消息消费02-主题与分区 自定义反序列化 拦截器 位移提交 位移管理 重平衡
点一下关注吧!!!非常感谢!!持续更新!!! 目前已经更新到了: Hadoop(已更完)HDFS(已更完)MapReduce(已更完&am…...

Google Gemma2 2B:语言模型的“小时代”到来?
北京时间8月1日凌晨(当地时间7月31日下午),Google发布了其Gemma系列开源语言模型的更新,在AI领域引发了巨大的震动。Google Developer的官方博客宣布,与6月发布的27B和9B参数版本相比,新的2B参数模型在保持…...

三线程顺序打印1-100
三线程顺序打印1-100 题目 三个线程顺序打印1-100; 解题 基本思路 首先需要创建三个线程, 确定使用线程1打印 num % 3 1 的数, 线程2打印 num % 3 2 的数, 线程3打印 num % 3 0 的数;使用 synchronized 同步锁让每次只有一个线程进行打印, 每个线程打印前先判断当前数是…...

中央处理器CPU
中央处理器CPU cpu的组成(从功能方面来看)cpu的执行过程★.取指令阶段★.解码阶段★.执行阶段 重点: 1.cpu的组成 2.cpu怎么执行程序(命令) cpu的组成(从功能方面来看) 寄存器:用来临…...

用Python实现AI人脸识别
实现AI人脸识别通常涉及到使用深度学习库,如TensorFlow或PyTorch,配合预训练的人脸识别模型。以下是一个使用Python和TensorFlow框架中的tensorflow_hub模块来加载和使用一个预训练的人脸识别模型的简单示例。 步骤 1: 安装必要的库 首先,你…...

MSPM0G3507_2024电赛自动行驶小车(H题)_问题与感悟
这次电赛题目选的简单了,还规定不能使用到摄像头,这让我之前学习的Opencv 4与树莓派无用武之地了,但我当时对于三子棋题目饶有兴趣,但架不住队友想稳奖,只能选择这个H题了...... 之后我还想抽空将这个E题三子棋题目做…...

C语言:指针(2)
一.数组名 在了解数组名前我们先看一段代码 int arr[10] {1,2,3,4,5,6,7,8,9,10}; int *p &arr[0]; 根据我们上一篇学习的知识,我们知道&arr[0]是数组第一个元素的地址,这时我们再看另一段代码的运行结果。 #include <stdio.h> int ma…...

数组——二维数组
数组(中) 二维数组 定义 二维数组本质上是一个行列式的组合,也就是说二维数组是有行和列两部分构成。二维数组数据是通过行列进行解读。 二维数组可被视为一个特殊的一维数组,相当于二维数组又是一个一维数组,只不过它的元素是一维数组。 …...

深入 Vue 组件与状态管理的教程
目录 深入 Vue 组件与状态管理的教程第一部分:深入组件1. 理解插槽(Slots)的使用1.1 基础插槽示例1.2 具名插槽1.3 作用域插槽 第二部分:Vue Router1. 学习 Vue Router 的基本配置1.1 基本路由配置1.2 嵌套路由1.3 路由参数 2. 导…...

Spring Boot 实现异步处理多个并行任务
在现代Web应用开发中,异步处理和多任务并行处理对于提高系统的响应性和吞吐量至关重要。Spring Boot 提供了多种机制来实现异步任务处理,本文将介绍如何利用这些机制来优化您的应用程序性能。 1. 引言 在高负载情况下,如果所有的请求都采用…...

TiDB系列之:使用Flink TiDB CDC Connector采集数据
TiDB系列之:使用Flink TiDB CDC Connector采集数据 一、依赖项二、Maven依赖三、SQL Client JAR四、如何创建 TiDB CDC 表五、连接器选项六、可用元数据七、特征一次性处理启动阅读位置多线程读取DataStream Source 八、数据类型映射 TiDB CDC 连接器允许从 TiDB 数…...

每日一道算法题 最接近的三数之和
题目 16. 最接近的三数之和 - 力扣(LeetCode) Python class Solution:def threeSumClosest(self, nums: List[int], target: int) -> int:nums.sort()nlen(nums)ans0min_diffinf # infinite 无穷for i in range(n-2):tmpnums[i]li1rn-1while l<…...

搭建自己的金融数据源和量化分析平台(六):下载并存储沪深两市上市公司财报
基于不依赖wind、某花顺等第三方平台数据的考虑,尝试直接从财报中解析三大报表进而计算ROE等财务指标,因此需要下载沪深两市的上市公司财报数据,便于后续从pdf中解析三大报表。 深市爬虫好做,先放深市爬虫: 根据时间段…...

C语言-常见关键字详解
一、const 关键字const用于声明常量,赋值后,其值不能再被修改。 示例: const int MAX_COUNT 100; 二、static static关键字在不同情境下有不同作用: 1.函数中的静态变量:保留变量状态,仅初始化一次&a…...

异步编程之std::future(一): 使用
目录 1.概述 2.std::future的基本用法 3.使用 std::shared_future 4.std::future的使用场景 5.总结 1.概述 在编程实践中,我们常常需要使用异步调用。通过异步调用,我们可以将一些耗时、阻塞的任务交给其他线程来执行,从而保证当前线程的…...