ios面试题.docx

上传人:b****5 文档编号:12369544 上传时间:2023-04-18 格式:DOCX 页数:20 大小:26.35KB
下载 相关 举报
ios面试题.docx_第1页
第1页 / 共20页
ios面试题.docx_第2页
第2页 / 共20页
ios面试题.docx_第3页
第3页 / 共20页
ios面试题.docx_第4页
第4页 / 共20页
ios面试题.docx_第5页
第5页 / 共20页
点击查看更多>>
下载资源
资源描述

ios面试题.docx

《ios面试题.docx》由会员分享,可在线阅读,更多相关《ios面试题.docx(20页珍藏版)》请在冰豆网上搜索。

ios面试题.docx

ios面试题

ios面试题

1.为什么说Objective-C是一门动态的语言?

1.object-c类的类型和数据变量的类型都是在运行是确定的,而不是在编译时确定。

例如:

多态特性,我们可以使用父类指针来指向子类对象,并且可以用来调用子类的方法。

运行时(runtime)特性,我们可以动态的添加方法,或者替换方法。

2.讲一下MVC和MVVM,MVP?

MVC:

简单来说就是,逻辑、试图、数据进行分层,实现解耦。

MVVM:

是Model-View-ViewMode模式的简称。

由视图(View)、视图模型(ViewModel)、模型(Model)三部分组成.比MVC更加释放控制器臃肿,将一部分逻辑(耗时,公共方法,网络请求等)和数据的处理等操作从控制器里面搬运到ViewModel中

MVVM的特点:

低耦合。

View可以独立于Model变化和修改,一个ViewModel可以绑定到不同的View上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。

可重用性。

可以把一些视图的逻辑放在ViewModel里面,让很多View重用这段视图逻辑。

独立开发。

开发人员可以专注与业务逻辑和数据的开发(ViewModel)。

设计人员可以专注于界面(View)的设计。

可测试性。

可以针对ViewModel来对界面(View)进行测试

MVP:

本小编没有接触,希望可以得到大家的帮助。

可以在下面留言。

3.为什么代理要用weak?

代理的delegate和dataSource有什么区别?

block和代理的区别?

代理是使用weak来修饰的。

1.使用weak是为了避免循环引用。

2.当使用weak修饰的属性,当对象释放的时候,系统会对属性赋值nil,object-c有个特性就是对nil对象发送消息也就是调用方法,不会cash。

delegate:

传递的是事件(even),代理可以让A对象通知B对象,我(A)发生的变化,前提B遵循了A的代理,并且实现了A的代理方法。

dataSource:

传递的是数据。

如果A对象声明了数据源,当我们创建A对象的时候,我们就该实现数据源,来告诉A,他所需要的一些数据。

例如:

tableView数据源方法,需要告诉它,我要实现几组cell,每组cell多少行cell,实现的cell什么样式,什么内容

同样delegate和dataSource,都是可以使用require和optional来修饰的。

代理和Block的区别

相同点:

代理和Block大多是我们都可以用来做倒序传值的。

我们都得注意避免循环引用。

不然我们去使用代理还是Block的时候,都需要判断它们是否实现

不同点:

代理使用weak修饰,代理必须先声明方法。

当我们调用代理的时候要判断是否已经实现。

block:

使用的是copy来修饰,block保存的是一段代码,其实也就是一个函数。

并且可以自动捕捉自动变量,如果想修改此自动变量,还必须使用__block修饰。

4.属性的实质是什么?

包括哪几个部分?

属性默认的关键字都有哪些?

@dynamic关键字和@synthesize关键字是用来做什么的?

属性是描述类的特征,也就是具备什么特性。

三个部分,带下划线的成员变量,get、setter方法。

默认关键字:

readwrite,assign,atomic;--是针对基本类型(NSInteger,BOOL,NSUInteger,int,等)

但是针对引用类型,默认:

strong,readwrite,atomic(例如:

NSString,NSArray,NSDictory等)

@dynamic:

修饰的属性,其getter和setter方法编译器是不会自动帮你生成。

必须自己是实现的。

@synthesize:

修饰的属性,其getter和setter方法编译器是会自动帮你生成,不必自己实现。

且指定与属性相对应的成员变量。

5.属性的默认关键字是什么?

默认关键字,基本数据:

atomic,readwrite,assign

普通的OC对象:

atomic,readwrite,strong

6.NSString为什么要用copy关键字,如果用strong会有什么问题?

(注意:

这里没有说用strong就一定不行。

使用copy和strong是看情况而定的

众所周知,我们知道,可变类型(NSMutableArray,NSMutableString等)是不可边类型(NSString,NSArray等)的子类,因为多态的原因,我们可以使用不可边类型去接受可变类型。

1.当我们使用strong修饰A不可边类型的时候,并且使用B可变类型给A赋值,再去修改可变类型B值的时候,A所指向的值也会发生改变。

引文strong只是让创建的对象引用计数器+1,并返回当前对象的内容地址,当我们修改B指向的内容的时候,A指向的内容也同样发生了改变,因为他们指向的内存地址是相同的,是一份内容。

2.当我们使用copy修饰A不可边类型的时候,并且使用B可变类型给A赋值,再去修改可变类型B值的时候,A所指向的值不会发生改变。

因为当时用copy的修饰的时候,会拷贝一份内容出来,并且返回指针给A,当我们修改B指向的内容的时候,A指向的内容是没有发生改变的。

因为A指向的内存地址和B指向的内存地址是不相同的,是两份内容

3.copy修饰不可边类型(NSString,NSArray等)的时候,且使用不可边类型进行赋值,表示浅拷贝,只拷贝一份指针,和strong修饰一样,当修饰的是可变类型(NSMutableArray,NSMutableString等)的时候,且使用可边类型进行赋值,表示深拷贝,直接拷贝新一份内容,到内存中。

表示两份内容。

image.png

7.如何令自己所写的对象具有拷贝功能?

如果想让自己的类具备copy方法,并返回不可边类型,必须遵循nscopying协议,并且实现

-(id)copyWithZone:

(NSZone*)zone

如果让自己的类具备mutableCopy方法,并且放回可变类型,必须遵守NSMutableCopying,并实现-(id)mutableCopyWithZone:

(nullableNSZone*)zone

注意:

再此说的copy对应不可边类型和mutableCopy对应不可边类型方法,都是遵从系统规则而已。

如果你想实现自己的规则,也是可以的。

8.可变集合类和不可变集合类的copy和mutablecopy有什么区别?

如果是集合是内容复制的话,集合里面的元素也是内容复制么?

可变使用copy表示深拷贝,不可变集合类使用copy的时候是浅拷贝。

可变集合类、不可边类型使用mutablecopy表示深拷贝

当是浅拷贝的时候,容器的内容是没有复制的。

如果是深拷贝的话,容器的内容都会收到一条copy消息,拷贝出新的内容,从新组成新的容器返回。

9.为什么IBOutlet修饰的UIView也适用weak关键字?

在xib或者Sb拖控件时,其实控件就加载到了父控件的subviews数组里面,进行了强引用,即使使用了weak,也不造成对象的释放。

10.nonatomic和atomic的区别?

atomic是绝对的线程安全么?

为什么?

如果不是,那应该如何实现?

nonatomic:

表示非原子,不安全,但是效率高。

atomic:

表示原子行,安全,但是效率低。

atomic:

不能绝对保证线程的安全,当多线程同时访问的时候,会造成线程不安全。

可以使用线程锁来保证线程的安全。

11.UICollectionView自定义layout如何实现?

实现一个自定义layout的常规做法是继承UICollectionViewLayout类,然后重载下列方法:

-(CGSize)collectionViewContentSize

返回collectionView的内容的尺寸

-(NSArray*)layoutAttributesForElementsInRect:

(CGRect)rect

返回rect中的所有的元素的布局属性

返回的是包含UICollectionViewLayoutAttributes的NSArray

UICollectionViewLayoutAttributes可以是cell,追加视图或装饰视图的信息,通过不同的UICollectionViewLayoutAttributes初始化方法可以得到不同类型的UICollectionViewLayoutAttributes:

layoutAttributesForCellWithIndexPath:

layoutAttributesForSupplementaryViewOfKind:

withIndexPath:

layoutAttributesForDecorationViewOfKind:

withIndexPath:

-(UICollectionViewLayoutAttributes)layoutAttributesForItemAtIndexPath:

(NSIndexPath)indexPath

返回对应于indexPath的位置的cell的布局属性

-(UICollectionViewLayoutAttributes)layoutAttributesForSupplementaryViewOfKind:

(NSString)kindatIndexPath:

(NSIndexPath*)indexPath

返回对应于indexPath的位置的追加视图的布局属性,如果没有追加视图可不重载

-(UICollectionViewLayoutAttributes*)layoutAttributesForDecorationViewOfKind:

(NSString)decorationViewKindatIndexPath:

(NSIndexPath)indexPath

返回对应于indexPath的位置的装饰视图的布局属性,如果没有装饰视图可不重载

-(BOOL)shouldInvalidateLayoutForBoundsChange:

(CGRect)newBounds

当边界发生改变时,是否应该刷新布局。

如果YES则在边界变化(一般是scroll到其他地方)时,将重新计算需要的布局信息。

12.用StoryBoard开发界面有什么弊端?

如何避免?

使用简单逻辑页面的跳转是可以使用sb的,开发比较块。

但是SB对于逻辑项目比较复杂的时候,开发起来比较慢。

不适合多人合作开发;也不利于版本的梗系和后期的维护。

使用sb在项目变异编译的时候,也都会直接加载到内存中,造成内存的浪费。

可以使用xib来代替,编辑复杂逻辑界面时候可以使用纯码编写。

13.进程和线程的区别?

同步异步的区别?

并行和并发的区别?

进程:

是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位.

线程:

是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.

同步:

阻塞当前线程操作,不能开辟线程。

异步:

不阻碍线程继续操作,可以开辟线程来执行任务。

并发:

当有多个线程在操作时,如果系统只有一个CPU,则它根本不可能真正同时进行一个以上的线程,它只能把CPU运行时间划分成若干个时间段,再将时间段分配给各个线程执行,在一个时间段的线程代码运行时,其它线程处于挂起状。

.这种方式我们称之为并发(Concurrent)。

并行:

当系统有一个以上CPU时,则线程的操作有可能非并发。

当一个CPU执行一个线程时,另一个CPU可以执行另一个线程,两个线程互不抢占CPU资源,可以同时进行,这种方式我们称之为并行(Parallel)。

区别:

并发和并行是即相似又有区别的两个概念,并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔内发生。

在多道程序环境下,并发性是指在一段时间内宏观上有多个程序在同时运行,但在单处理机系统中,每一时刻却仅能有一道程序执行,故微观上这些程序只能是分时地交替执行。

倘若在计算机系统中有多个处理机,则这些可以并发执行的程序便可被分配到多个处理机上,实现并行执行,即利用每个处理机来处理一个可并发执行的程序,这样,多个程序便可以同时执行。

14.线程间通信?

当使用dispath-async函数开辟线程执行任务的完成时,我们需要使用dispatch_async(dispatch_get_main_queue(),^{});函数会到主线程内刷新UI。

并完成通信

15.GCD的一些常用的函数?

(group,barrier,信号量,线程同步)

我们使用队列组来开辟线程时,队列组中的队列任务是并发,当所有的队列组中的所有任务完成时候,才可以调用队列组完成任务。

/**创建自己的队列*/

dispatch_queue_tdispatchQueue=dispatch_queue_create("ted.queue.next",DISPATCH_QUEUE_CONCURRENT);

/**创建一个队列组*/

dispatch_group_tdispatchGroup=dispatch_group_create();

/**将队列任务添加到队列组中*/

dispatch_group_async(dispatchGroup,dispatchQueue,^(){

NSLog(@"dispatch-1");

});

/**将队列任务添加到队列组中*/

dispatch_group_async(dispatchGroup,dispatchQueue,^(){

NSLog(@"dspatch-2");

});

/**队列组完成调用函数*/

dispatch_group_notify(dispatchGroup,dispatch_get_main_queue(),^(){

NSLog(@"end");

})barrier:

表示栅栏,当在并发队列里面使用栅栏时候,栅栏之前的并发任务开始并发执行,执行完毕后,执行栅栏内的任务,等栅栏任务执行完毕后,再并发执行栅栏后的任务。

dispatch_queue_tconcurrentQueue=dispatch_queue_create("my.concurrent.queue",DISPATCH_QUEUE_CONCURRENT);

dispatch_async(concurrentQueue,^(){

NSLog(@"dispatch-1");

});

dispatch_async(concurrentQueue,^(){

NSLog(@"dispatch-2");

});

dispatch_barrier_async(concurrentQueue,^(){

NSLog(@"dispatch-barrier");

});

dispatch_async(concurrentQueue,^(){

NSLog(@"dispatch-3");

});

dispatch_async(concurrentQueue,^(){

NSLog(@"dispatch-4");

});信号量:

Semaphore是通过‘计数’的方式来标识线程是否是等待或继续执行的。

信号量

dispatch_semaphore_create(int)//创建一个信号,并初始化信号的计数大小

/*等待信号,并且判断信号量,如果信号量计数大于等于你创建时候的信号量的计数,就可以通过,继续执行,并且将你传入的信号计数减1,

*如果传入的信号计数小于你创建的计数,就表示等待,等待信号计数的变化

*如果等待的时间超过你传入的时间,也会继续下面操作

*第一个参数:

semaphore表示信号量

*第二个参数:

表示等待的时间

*返回int如果传入的信号计数大于等于你创建信号的计数时候,返回0.反之,返回的不等于0

*/

intresult=dispatch_semaphore_wait(dispatch_semaphore_tsemaphore,timeoutTime);//表示等待,也是阻碍线程

//表示将信号技术+1

dispatch_semaphore_signl(dispatch_semaphore_tsemaphore);实现线程的同步的方法:

串行队列,分组,信号量。

也是可以使用并发队列。

//加入队列

dispatch_async(concurrentQueue,^{

//1.先去网上下载图片

dispatch_sync(concurrentQueue,^{

});

//2.在主线程展示到界面里

dispatch_sync(dispatch_get_main_queue(),^{});

});

16.如何使用队列来避免资源抢夺?

当我们使用多线程来访问同一个数据的时候,就有可能造成数据的不准确性。

这个时候我么可以使用线程锁的来来绑定。

也是可以使用串行队列来完成。

如:

fmdb就是使用FMDatabaseQueue,来解决多线程抢夺资源。

17.数据持久化的几个方案(fmdb用没用过)

持久化方案:

plist,存储字典,数组比较好用

preference:

偏好设置,实质也是plist

NSKeyedArchiver:

归档,可以存储对象

sqlite:

数据库,经常使用第三方来操作,也就是fmdb

coreData:

也是数据库储存,苹果官方的

18.说一下appdelegate的几个方法?

从后台到前台调用了哪些方法?

第一次启动调用了哪些方法?

从前台到后台调用了哪些方法?

1029210

(1).gif

19.NSCache优于NSDictionary的几点?

1.nscache是可以自动释放内存的。

2.nscache是线程安全的,我们可以在不同的线程中添加,删除和查询缓存中的对象。

3.一个缓存对象不会拷贝key对象。

20.知不知道DesignatedInitializer?

使用它的时候有什么需要注意的问题?

个人理解:

初始化函数,如果你想自定义初始化函数时,也是必须要初始化父类,以来保证可以继承父类的一些方法或者属性。

DesignatedInitializer

21.实现description方法能取到什么效果?

description是nsobject的一个实例的方法,返回的是一个nsstring。

当我们使用nslog打印的时候,打印出来的一般都是对象的内存地址,如果我们实现description方法时,我们就可以使用nslog打印对象的时候,我们可以把它里面的属性值和内存地址一起打印出来.打印什么,就是看你写什么了。

-(NSString*)description{

NSString*string=[NSStringstringWithFormat:

@"",self,self.name,self.age];

returnstring;

}

22.objc使用什么机制管理对象内存?

使用内存管理计数器,来管理内存的。

当内存管理计数器为0的时候,对象就会被释放。

中级

Block

1.block的实质是什么?

一共有几种block?

都是什么情况下生成的?

block:

本质就是一个object-c对象.

block:

存储位置,可能分为3个地方:

代码去,堆区、栈区(ARC情况下会自动拷贝到堆区,因此ARC下只能有两个地方:

代码去、堆区)

代码区:

不访问栈区的变量(如局部变量),且不访问堆区的变量(alloc创建的对象),此时block存放在代码去。

堆区:

访问了处于栈区的变量,或者堆区的变量,此时block存放在堆区。

–需要注意实际是放在栈区,在ARC情况下会自动拷贝到堆区,如果不是ARC则存放在栈区,所在函数执行完毕就回释放,想再外面调用需要用copy指向它,这样就拷贝到了堆区,strong属性不会拷贝、会造成野指针错区。

2.为什么在默认情况下无法修改被block捕获的变量?

__block都做了什么?

默认情况下,block里面的变量,拷贝进去的是变量的值,而不是指向变量的内存的指针。

当使用__block修饰后的变量,拷贝到block里面的就是指向变量的指针,所以我们就可以修改变量的值。

3.模拟一下循环引用的一个情况?

block实现界面反向传值如何实现?

Person*p=[[Personalloc]init];

[psetPersonBlock:

^(NSString*str){

p.name=str;

}];

Runtime

1.objc在向一个对象发送消息时,发生了什么?

根据对象的isa指针找到类对象id,在查询类对象里面的methodLists方法函数列表,如果没有在好到,在沿着superClass,寻找父类,再在父类methodLists方法列表里面查询,最终找到SEL,根据id和SEL确认IMP(指针函数),在发送消息;

3.什么时候会报unrecognizedselector错误?

iOS有哪些机制来避免走到这一步?

当发送消息的时候,我们会根据类里面的methodLists列表去查询我们要动用的SEL,当查询不到的时候,我们会一直沿着父类查询,当最终查询不到的时候我们会报unrecognizedselector错误

当系统查询不到方法的时候,会调用+(BOOL)resolveInstanceMethod:

(SEL)sel动态解释的方法来给我一次机会来添加,调用不到的方法。

或者我们可以再次使用-(id)forwardingTargetForSelector:

(SEL)aSelector重定向的方法来告诉系统,该调用什么方法,一来保证不会崩溃。

4.能否向编译后得到的类中增加实例变量?

能否向运行时创建的类中添加实例变量?

为什么?

1.不能向编译后得到的类增加实例变量

2.能向运行时创建的类中添加实例变量

解释:

1.编译后的类已经注册在runtime中,类结构体中的objc_ivar_list实例变量的链表和instance_size实例变量的内存大小已经确定,runtime会调用class_setvarlayout或class_setWeaklvarLayout来处理strongweak引用.所以不能向存在的类中添加实例变量

2.运行时创建的类是可以添加实例变量,调用class_addIvar函数.但是的在调用objc_allocateClassPair之后,objc_registerClassPair之前,原因同上.

5.runtime如何实现weak变量的自动置nil?

runtime对注册的类,会进行布局,对于weak对象会放入一个hash表中。

用weak指向的对象内存地址作为key,当此对象的引用计数为0的时候会dealloc,假如weak指向的对象内存地址是a,那么就会以a为键,在这个weak表中搜索,找到所有以a为键的weak对象,从而设置为nil。

6.给类添加一个属性后,在类结构体里哪些元素会发生变化?

instance_size:

实例的内存大小

objc_ivar_list*ivars:

属性列表

RunL

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 >

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1