最新iOS开发常见面试题总结一!(附答案)

这篇博客总结了iOS开发中的核心面试题,涵盖了类与结构体的区别、自动释放池的工作原理、Runtime的应用、KVC与KVO的底层原理和使用场景、持久化方式、UIViewController的生命周期、事件传递机制等。同时,博主分享了如何理解和应用这些知识点,并提供了项目实践中的经验,适合iOS开发者复习和准备面试。
摘要由CSDN通过智能技术生成

1.iOS 类(class)和结构体(struct)有什么区别?

Swift 中,类是引用类型,结构体是值类型。值类型在传递和赋值时将进行复制,而引用类型则只会使用引用对象的一个"指向"。所以他们两者之间的区别就是两个类型的区别。

举个简单的例子,代码如下

class Temperature {
  var value: Float = 37.0
}

class Person {
  var temp: Temperature?

  func sick() {
    temp?.value = 41.0
  }
}

let A = Person()
let B = Person()
let temp = Temperature()

A.temp = temp
B.temp = temp

A.sick() 上面这段代码,由于 Temperature 是 class ,为引用类型,故 A 的 temp 和 B 的 temp指向同一个对象。A 的 temp修改了,B 的 temp 也随之修改。这样 A 和 B 的 temp 的值都被改成了41.0。如果将 Temperature 改为 struct,为值类型,则 A 的 temp 修改不影响 B 的 temp。

内存中,引用类型诸如类是在堆(heap)上,而值类型诸如结构体实在栈(stack)上进行存储和操作。相比于栈上的操作,堆上的操作更加复杂耗时,所以苹果官方推荐使用结构体,这样可以提高 App 运行的效率。

class有这几个功能struct没有的:

class可以继承,这样子类可以使用父类的特性和方法 类型转换可以在runtime的时候检查和解释一个实例的类型 可以用deinit来释放资源 一个类可以被多次引用 struct也有这样几个优势:

结构较小,适用于复制操作,相比于一个class的实例被多次引用更加安全。 无须担心内存memory leak或者多线程冲突问题

作为一个开发者,有一个学习的氛围跟一个交流圈子特别重要,这是一个我的iOS开发交流群:130595548,不管你是小白还是大牛都欢迎入驻 ,让我们一起进步,共同发展!(群内会免费提供一些群主收藏的免费学习书籍资料以及整理好的几百道面试题和答案文档!)

2.iOS自动释放池是什么,如何工作 ?

当您向一个对象发送一个autorelease消息时,Cocoa就会将该对象的一个引用放入到最新的自动释放池。它仍然是个正当的对象,因此自动释放池定义的作用域内的其它对象可以向它发送消息。当程序执行到作用域结束的位置时,自动释放池就会被释放,池中的所有对象也就被释放。

1.object-c 是通过一种"referring counting"(引用计数)的方式来管理内存的, 对象在开始分配内存(alloc)的时候引用计数为一,以后每当碰到有copy,retain的时候引用计数都会加一, 每当碰到release和autorelease的时候引用计数就会减一,如果此对象的计数变为了0, 就会被系统销毁.

2.NSAutoreleasePool 就是用来做引用计数的管理工作的,这个东西一般不用你管的.

3.autorelease和release没什么区别,只是引用计数减一的时机不同而已,autorelease会在对象的使用真正结束的时候才做引用计数减一.

3.iOS你在项目中用过 runtime 吗?举个例子

Objective-C 语言是一门动态语言,编译器不需要关心接受消息的对象是何种类型,接收消息的对象问题也要在运行时处理。

pragramming 层面的 runtime 主要体现在以下几个方面:

1.关联对象 Associated Objects
2.消息发送 Messaging
3.消息转发 Message Forwarding
4.方法调配 Method Swizzling
5.“类对象” NSProxy Foundation | Apple Developer Documentation
6.KVC、KVO About Key-Value Coding

4.KVC /KVO的底层原理和使用场景

1 KVC(KeyValueCoding)
1.1 KVC 常用的方法

(1)赋值类方法
- (void)setValue:(nullable id)value forKey:(NSString *)key;
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;
- (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key;
- (void)setValuesForKeysWithDictionary:(NSDictionary<NSString *, id> *)keyedValues;

(2)取值类方法
// 能取得私有成员变量的值
- (id)valueForKey:(NSString *)key;
- (id)valueForKeyPath:(NSString *)keyPath;
- (NSDictionary *)dictionaryWithValuesForKeys:(NSArray *)keys;

1.2 KVC 底层实现原理

当一个对象调用setValue:forKey: 方法时,方法内部会做以下操作:
 1.判断有没有指定key的set方法,如果有set方法,就会调用set方法,给该属性赋值
 2.如果没有set方法,判断有没有跟key值相同且带有下划线的成员属性(_key).如果有,直接给该成员属性进行赋值
 3.如果没有成员属性_key,判断有没有跟key相同名称的属性.如果有,直接给该属性进行赋值
 4.如果都没有,就会调用 valueforUndefinedKey 和setValue:forUndefinedKey:方法

1.3 KVC 的使用场景
1.3.1 赋值
(1) KVC 简单属性赋值

Person *p = [[Person alloc] init];
//    p.name = @"jack";
//    p.money = 22.2;
使用setValue: forKey:方法能够给属性赋值,等价于直接给属性赋值
[p setValue:@"rose" forKey:@"name"];
[p setValue:@"22.2" forKey:@"money"];

(2) KVC复杂属性赋值

//给Person添加 Dog属性
   Person *p = [[Person alloc] init];
   p.dog = [[Dog alloc] init];
  // p.dog.name = @"阿黄";

1)setValue: forKeyPath: 方法的使用
  //修改p.dog 的name 属性
    [p.dog setValue:@"wangcai" forKeyPath:@"name"];
    [p setValue:@"阿花" forKeyPath:@"dog.name"];

2)setValue: forKey: 错误用法
    [p setValue:@"阿花" forKey:@"dog.name"];
    NSLog(@"%@", p.dog.name);

3)直接修改私有成员变量
[p setValue:@"旺财" forKeyPath:@"_name"];

(3) 添加私有成员变量

Person 类中添加私有成员变量_age
[p setValue:@"22" forKeyPath:@"_age"];

1.3.2 字典转模型

(1)简单的字典转模型
+(instancetype)videoWithDict:(NSDictionary *)dict
{
   JLVideo *videItem = [[JLVideo alloc] init];
   //以前
//    videItem.name = dict[@"name"];
//    videItem.money = [dict[@"money"] doubleValue] ;
   
   //KVC,使用setValuesForKeysWithDictionary:方法,该方法默认根据字典中每个键值对,调用setValue:forKey方法
   // 缺点:字典中的键值对必须与模型中的键值对完全对应,否则程序会崩溃
   [videItem setValuesForKeysWithDictionary:dict];
   return videItem;
}

(2)复杂的字典转模型
注意:复杂字典转模型不能直接通过KVC 赋值,KVC只能在简单字典中使用,比如:
   NSDictionary *dict = @{
                      @"name" : @"jack",
                      @"money": @"22.2",
                      @"dog" : @{
                              @"name" : @"wangcai",
                              @"money": @"11.1",

                              }

                      };
  JLPerson *p = [[JLPerson alloc]init]; // p是一个模型对象
  [p setValuesForKeysWithDictionary:dict];
内部转换原理:
//    [p setValue:@"jack" forKey:@"name"];
//    [p setValue:@"22.2" forKey:@"money"];
//    [p setValue:@{
//                  @"name" : @"wangcai",
//                  @"money": @"11.1",
//
//                  } forKey:@"dog"]; //给 dog赋值一个字典肯定是不对的

(3)KVC解析复杂字典的正确步骤
  NSDictionary *dict = @{
                      @"name" : @"jack",
                      @"money": @"22.2",
                      @"dog" : @{
                              @"name" : @"wangcai",
                              @"price": @"11.1",
                              },
                      //人有好多书
                      @"books" : @[
                              @{
                                  @"name" : @"5分钟突破iOS开发",
                                  @"price" : @"19.8"
                                  },
                              @{
                                  @"name" : @"3分钟突破iOS开发",
                                  @"price" : @"24.8"
                                  },
                              @{
                                  @"name" : @"1分钟突破iOS开发",
                                  @"price" : @"29.8"
                               
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值