ios 面试题

前言

2019年iOS面试题中看到的一些面试题,自己搜索答案将其整理放到一起。

基础

1.我们说的Objective-C是动态运行时语言是什么意思

  • object-c类的类型和数据变量的类型都是在运行是确定的,而不是在编译时确定。例如:多态特性,我们可以使用父类对象来指向子类对象,并且可以用来调用子类的方法。运行时(runtime)特性,我们可以动态的添加方法,或者替换方法。

2.讲一下MVC和MVVM,MVP?

  • MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,Model 呈现数据,View 呈现用户界面,而 View Controller 调节它两者之间的交互。
  • MVVM全名是Model View View-Model。
    ViewModel将表示逻辑从 Controller 移出放到一个新的对象里,即 View Model。就是那些将 Model 数据转换为 View 可以呈现的东西的事情,例如将一个 NSDate 转换为一个格式化过的 NSString。
  • MVP全名是Model-view-presenter,是使用者界面设计模式的一种。
    Model 定义使用者界面所需要被显示的数据模型,一个模型包含着相关的业务逻辑。View 视图为呈现使用者界面的终端,用以表现来自 Model 的数据,和使用者命令路由再经过 Presenter 对事件处理后的数据。

3.为什么代理要用weak?代理的delegate和dataSource有什么区别?block和代理的区别?

  • 防止循环引用。dataSource负责数据,delegate负责调用方法。
  • block本质上是一个OC对象,因为它的内部也有isa指针,代理是一种设计模式
  • 1.从源头上理解和区别block和delegate
    delegate运行成本低,block的运行成本高。
    block出栈需要将使用的数据从栈内存拷贝到堆内存,当然对象的话就是加计数,使用完或者block置nil后才消除。delegate只是保存了一个对象指针,直接回调,没有额外消耗。就像C的函数指针,只多做了一个查表动作。
  • 2.从使用场景区别block和delegate
    有多个相关方法。假如每个方法都设置一个 block, 这样会更麻烦。而 delegate 让多个方法分成一组,只需要设置一次,就可以多次回调。当多于 3 个方法时就应该优先采用 delegate。当1,2个回调时,则使用block。
    delegate更安全些,比如: 避免循环引用。使用 block 时稍微不注意就形成循环引用,导致对象释放不了。这种循环引用,一旦出现就比较难检查出来。而 delegate 的方法是分离开的,并不会引用上下文,因此会更安全些。

4.如何访问并修改一个类的私有属性
1.KVC(键值编码)

 Person *p = [Person new];
  //修改私有属性的值
  [p setValue:@"yyMae" forKey:@"name"];
  //访问私有属性的值
  NSString *name = [p valueForKey:@"name"];

2.通过runtime获取或修改一个类私有属性的值

 Person *p = [Person new];
  // IVar是runtime声明的一个宏 
  unsigned int count = 0; //count记录变量的数量
  // 获取类的所有属性变量 
  Ivar *members = class_copyIvarList([Person class], &count); 
  for (int i = 0; i < count; i++) { 
    Ivar ivar = members[i]; 
    // 取得属性名并转成字符串类型
    const char *memberName = ivar_getName(ivar);               
    NSLog(@"%s",memberName); 
  }
  Ivar name = members[0]; 
    // 修改属性值 
  object_setIvar(Person, name, @"yyMae"); 

5.objc使用什么机制管理对象内存?
引用计数,管理方式 1.MRC 2.ARC


block

1.block的本质是什么?一共有几种block?都是什么情况下生成的?
    block的一些常用问答

2.使用系统的某些block api,是否考虑引用循环问题?
系统的某些block api中,UIView的block版本写动画时不需要考虑,但也有一些api 需要考虑:所谓“引用循环”是指双向的强引用,所以那些“单向的强引用”(block 强引用 self )没有问题,比如这些:

[UIView  animateWithDuration:durationanimations:^{ [self.superviewlayoutIfNeeded]; }];

[[NSOperationQueuemainQueue]addOperationWithBlock:^{ self.someProperty= xyz; }];

[[NSNotificationCenterdefaultCenter]addObserverForName:@"someNotification"object:nilqueue:

[NSOperationQueuemainQueue]usingBlock:^(NSNotification* notification) { self.someProperty= xyz; }];

但如果你使用一些参数中可能含有 ivar 的系统 api ,如 GCD 、NSNotificationCenter就要小心一点:比如GCD 内部如果引用了 self,而且 GCD 的其他参数是 ivar,则要考虑到循环引用:

__weak__typeof__(self) weakSelf = self;
dispatch_group_async(_operationsGroup, _operationsQueue, ^{
	__typeof__(self) strongSelf = weakSelf;
	[strongSelf doSomething];
	[strongSelf doSomethingElse];
	} );

检测代码中是否存在循环引用问题,可使用 Facebook 开源的一个检测工具FBRetainCycleDetector


Runtime

1.runtime如何实现weak属性?如何实现weak变量的自动置nil?
weak 对象会放入一个 hash 表中。
用 weak 指向的对象内存地址作为 key,当此对象的引用计数为0的时候会 dealloc。
假如 weak 指向的对象内存地址是addr,那么就会以addr为键, 在这个 weak 表中搜索,找到所有以addr为键的 weak 对象,从而设置为 nil。

2.runtime如何通过selector找到对应的IMP地址?

在寻找IMP的地址时,runtime提供了两种方法

// IMP class_getMethodImplementation(Class cls, SEL name); class_getMethodImplementation(objc_getMetaClass("A"),@selector(methodName));
// IMP method_getImplementation(Method m); class_getMethodImplementation([A class],@selector(methodName));

3.能否向编译后得到的类中增加实例变量?能否向运行时创建的类中添加实例变量?为什么?
1.不能向编译后得到的类增加实例变量
2.能向运行时创建的类中添加实例变量
解释:
1.编译后的类已经注册在runtime中,类结构体中的objc_ivar_list实例变量的链表和instance_size实例变量的内存大小已经确定,runtime会调用class_setvarlayout或class_setWeaklvarLayout来处理strong weak引用.所以不能向存在的类中添加实例变量
2.运行时创建的类是可以添加实例变量,调用class_addIvar函数.但是的在调用objc_allocateClassPair之后,objc_registerClassPair之前,原因同上

4.在开发中如何使用runtime?什么应用场景?
Runtime重要知识点以及使用场景

类结构

1.isa指针?

在Objective-C中,任何类的定义都是对象。类和类的实例(对象)没有任何本质上的区别。任何对象都有isa指针

每个实例对象有个isa的指针,他指向对象的类,而Class里也有个isa的指针, 指向meteClass(元类)。元类保存了类方法的列表。当类方法被调用时,先会从本身查找类方法的实现,如果没有,元类会向他父类查找该方法。同时注意的是:元类(meteClass)也是类,它也是对象。元类也有isa指针,它的isa指针最终指向的是一个根元类(root meteClass).根元类的isa指针指向本身,这样形成了一个封闭的内循环。

2.类方法和实例方法有什么区别?

1、在类方法中不能调用实例方法,只能访问和自己一样的类方法,但实例方法可以访问类方法和实例方法。
2、在类方法中不能引用实例变量(用static修饰的变量),但实例方法可以引用成员变量和实例变量。
3、在类方法中不能使用super、this关键字。
4、类方法不能被覆盖,但实例方法可以被覆盖。
5、类方法的调用是:类名.类方法,而实例方法的调用必须new出一个对象,即:对象.实例方法。

3.介绍一下分类,能用分类做什么?内部是如何实现的?它为什么会覆盖掉原来的方法?

主要作用是在不改变原有类的前提下,动态地给这个类添加一些方法。
category内部实现原理


未完待续···

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值