iOS面试之属性关键字(二):常见面试题

news2024/11/15 20:02:52

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. 实例方法中也可以调用类方法(通过类名)


 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1971608.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何将本地下载的切片电影进行合成一个视频

合成后的时长1:41 没有合成前是50个电影切片 注明:电影切片不是真实的切片名称而是自定义从0-50的数字 import requests # with open("电影.m3u8","r") as f: # n0 # for line in f: # if line.startswith("#"): …

SpringBoot项目如何安装Selenium自动化(详解)

目录 一、打开intellij idea,创建Maven项目 二、添加依赖 三、在Test路径下创建自动化文件 3.1 项目结构 3.2 代码 四、运行自动化 前言: java版本最低要求为8。电脑至少已安装一种浏览器,如:Chrome(推荐)、…

十日Python项目——第五日(商品数据)

#前言: 在最近十天我会用Python做一个购物类项目,会用到DjangoMysqlRedisVue等。 今天是第五天,主要负责撰写响应具体的商品数据。若是有不懂大家可以先阅读我的前四篇博客以能够顺承。 若是大家基础有不懂的,小编前面已经关于…

RJ45空包弹网口描述与应用

RJ45空包弹网口,通常指的是RJ45接口的空芯线缆(通常称为“空包”)和相应的连接器。这种线缆和连接器组合常用于网络布线中,特别是在需要将网络信号从一端传输到另一端,同时保持信号完整性和隔离性的场合。 描述&#…

C++初阶:list的使用和模拟实现

关于list可以先看一下这个文档:list文档 一.list的介绍和使用 1.1 list的介绍 list实际上就是链表,是带头双向循环链表。 1.2 list的使用 list的使用跟我们以前用C语言实现时的一样。push,pop,insert等等。 1.2.1list的构造 …

【从零开始一步步学习VSOA开发】开发环境搭建

开发环境搭建 开发 VSOA 首先需要搭建开发环境,这里讲解 Windows 下 C/C 开发环境搭建方法。 下载 IDE 并申请授权码 SylixOS 的开发和部署需要 RealEvo-IDE 的支持,因此您需要先获取 RealEvo-IDE 的安装包和注册码。 RealEvo-IDE 分为体验版和商业版…

简单的 微服务netflix 学习

简单的 微服务netflix 学习 一.Eureka 学习 1. 服务简单搭建 1.1 首先确定pom文件 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-…

FPGA入门系列:计数器

目录 微信公众号获取更多FPGA相关源码&#xff0c;且微信公众号为首发&#xff0c;第一时间获取最新文章&#xff1a; 计数器是一种典型的时序器件&#xff0c;常用于对时钟脉冲的个数进行计数&#xff0c;还用于定时、分频、产生同步脉冲等 按触发方式分&#xff1a;同步计数…

国内SSL证书颁发机构哪家服务更优质?

SSL证书作为保障网站数据传输安全的关键工具&#xff0c;其重要性不言而喻。选择一个可靠的SSL证书代理商&#xff0c;不仅能够提供多样化的证书类型&#xff0c;而且能在众多品牌中进行比较&#xff0c;选择最适合自己的、性价比更高的产品。此外&#xff0c;优质的代理商还能…

JAVA项目基于Spring Boot的多媒体素材库

目录 一、前言 二、技术介绍 三、项目实现流程 四、论文流程参考 五、核心代码截图 专注于大学生实战开发、讲解和毕业答疑等辅导&#xff0c;获取源码后台 一、前言 信息化管理时代已至&#xff0c;计算机与互联网技术深度融合于生活点滴。本系统源于对用户需求的深刻洞…

Spark学习之SaprkCore

FlinkCore 1、JavaAPI 1、创建一个Topic并写入数据 向Kafka写数据 如果topic不存在则会自动创建一个副本和分区数都是1的topic package com.shujia.kafka;import org.apache.kafka.clients.producer.KafkaProducer; import org.apache.kafka.clients.producer.ProducerRecord…

JAVASpring学习Day2

面向切面编程 (AOP) 面向切面编程是一种编程范式&#xff0c;用于在程序中分离关注点&#xff0c;例如日志记录、事务管理和安全性。它主要由以下几个关键组成部分构成&#xff1a; 连接点 (Join Point)&#xff1a;在程序执行过程中可以插入切面的点&#xff0c;通常是方法的…

I2C 设备驱动编写流程

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、修改设备树1、 IO 修改或添加2、在 i2c1 节点追加 ap3216c 子节点3、查看设备树节点创建是否成功 二、AP3216C 驱动编写 前言 提示&#xff1a;这里可以添…

9.11 与 9.9 哪个大? 大模型幻觉从何而来?用最通俗的例子讲清楚大模型原理。

​如下图&#xff0c;我们使用用 gpt-4-turbo 模型为例&#xff0c;问9.11 与 9.9 哪个大&#xff0c;并让他一步一步给出分析步骤。你会发现&#xff0c;它开始了胡说八道&#xff0c;这就是“大模型幻觉” 。 那么问题来了&#xff0c;为什么会出现这种结果&#xff1f;幻觉从…

【Python代码】如何在多个Excel文件中高效找出含有特定关键词的文件?

点击上方"蓝字" 关注木易巷&#xff01; 哈喽&#xff0c;大家好&#xff0c;木易巷来啦&#xff01; 想象一下&#xff0c;如果你有一个文件夹&#xff0c;里面堆满了近百个Excel文件&#xff0c;你需要从中找出包含特定关键词文本的文件。文件格式不统一&#xf…

仓颉语言 -- 宏

使用新版本 &#xff08;2024-07-19 16:10发布的&#xff09; 1、宏的简介 宏可以理解为一种特殊的函数。一般的函数在输入的值上进行计算&#xff0c;然后输出一个新的值&#xff0c;而宏的输入和输出都是程序本身。在输入一段程序&#xff08;或程序片段&#xff0c;例如表达…

【OpenCV C++20 学习笔记】提取水平和垂直线条

提取水平和垂直线条 原理实操——去除五线谱的五线二进制化提取垂直对象完善边缘和最终输出图片黑白反转平滑 完整代码 其他图片元素提取实践提取水平线条提取音符轮廓 原理 在腐蚀和膨胀操作中&#xff0c;通过卷积核(kernel)&#xff0c;或者结构元素(structuring element)&…

vue-router核心TS类型

NavigationFailureType 枚举&#xff1a; export declare enum NavigationFailureType {/*** An aborted navigation is a navigation that failed because a navigation* guard returned false or called next(false)*/aborted 4,/*** A cancelled navigation is a navigati…

arduino程序-MC猜数字5、6(基础知识)

arduino程序-MC猜数字5、6&#xff08;基础知识&#xff09; 1-23 MC猜数字-5 自定义函数自定义函数自定义清理显示内容函数displayClear&#xff08;&#xff09;带参数函数displayNumber带参数、返回值的函数 1-24 MC猜数字-6 完成制作显示0~9数字函数改造产生随机数字函数改…

嵌入式人工智能(42-基于树莓派4B的红外遥控)

1、简介 红外遥控想必对大家来说都不陌生&#xff0c;红外也属于无线通信的一种&#xff0c;只要是无线通信&#xff0c;必然要用电磁波&#xff0c;要理解无线通信的本质和原理&#xff0c;不管用哪个频段都要学习电磁场与电磁波&#xff0c;这是一个难度很大的课&#xff0c…