iOS面试题<一>

1、        如何用GCD同步若干个异步调用?(如根据若干个url异步加载多张图片,然后在都下载完成后合成一张整图)

总体上说:  使用dispatch group,然后 wait forever 等待完成, 或者采取 group notify 来通知回调。

  细节:

 1. 创建异步队列

 2. 创建dispatch_group dispatch_group_t = dispatch_group_create()

       3.通过组来执行异步下载任务

 dispatch_group_async(queueGroup, aQueue,^{   

       NSLog(@"下载图片.");   

 });

4.等到所有任务完成   dispatch_group_wait(queueGroup,DISPATCH_TIME_FOREVER);

5.合成图片

2、        @synthesize和@dynamic区别

在声明property属性后,有2种实现选择

@synthesize

编译器期间,让编译器自动生成getter/setter方法。

当有自定义的存或取方法时,自定义会屏蔽自动生成该方法

@dynamic

告诉编译器,不自动生成getter/setter方法,避免编译期间产生警告

然后由自己实现存取方法

@property就是编译其自动帮我们生成一个私有的成员变量和setter与getter方法的声明和实现

3、        weak关键字

strong:适用于OC对象,作用和非ARC中的retain作用相同,它修饰的成员变量为强指针类型;

weak:适用于OC对象,作用和非ARC中的assign作用相同,修饰的成员变量为弱指针类型;在ARC中,出现循环引用的时候,必须要有一端使用weak

      assign: 用于非指针变量。用于基础数据类型。直接进行赋值,这也是默认的。setter方法直接赋值,而不进行retain操作

retain:用于指针变量。setter方法对参数进行release旧值,再retain新值。

copy:它指出,在赋值时使用传入值的一份拷贝

      readwrite: 产生setter\getter方法

readonly: 只产生简单的getter,没有setter。

      copy: setter方法进行Copy操作,与retain一样

      nonatomic: 禁止多线程,变量保护,提高性能

4、        iOS容易造成循环引用的三种场景

循环引用可以简单理解为A引用了B,而B又引用了A,双方都同时保持对方的一个引用,导致任何时候引用计数都不为0,始终无法释放。

(1)计时器NSTimer:一方面,NSTimer经常会被作为某个类的成员变量,而NSTimer初始化时要指定self为target,容易造成循环引用。另一方面,若timer一直处于validate的状态,则其引用计数将始终大于0。

解决方案:

在于-(void)cleanTimer函数的调用时机不对,显然不能想当然地放在调用者的dealloc中。一个比较好的解决方法是开放这个函数,让Friend的调用者显式地调用来清理现场

(2)block:某个类将block作为自己的属性变量,然后该类在block的方法体里面又使用了该类本身

解决方案:

1) ARC环境下:ARC环境下可以通过使用_weak声明一个代替self的新变量代替原先的self,通过这种方式告诉block,不要在block内部对self进行强制strong引用

2) 2)MRC环境下:使用_block即可,这样的意思是告诉block:不要在内部对self进行retain了

(3)委托delegate

声明delegate时请用assign(MRC)或者weak(ARC)

5、        IOS 四种保存数据的方式

1.NSKeyedArchiver:采用归档的形式来保存数据,该数据对象需要遵守NSCoding协议,并且该对象对应的类必须提供encodeWithCoder:和initWithCoder:方法。前一个方法告诉系统怎么对对象进行编码,而后一个方法则是告诉系统怎么对对象进行解码

归档的形式来保存数据,只能一次性归档保存以及一次性解压。所以只能针对小量数据

2.NSUserDefaults:用来保存应用程序设置和属性、用户保存的数据。用户再次打开程序或开机后这些数据仍然存在。NSUserDefaults可以存储的数据类型包括:NSData、NSString、NSNumber、NSDate、NSArray、NSDictionary。如果要存储其他类型,则需要转换为前面的类型,才能用NSUserDefaults存储。

3.SQLite:采用SQLite数据库来存储数据。

第一步:需要添加SQLite相关的库以及头文件:在项目文件的Build Phases下,找到Link Binary Library(ies),添加libsqlite3.0.dylib

第二步:开始使用SQLite

4.CoreData.Core Data是数据持久化存储的最佳方式。数据最终的存储类型可以是:SQLite数据库,XML,二进制,内存里,或自定义数据类型

好处:能够合理管理内存,避免使用sql的麻烦,高效

构成:

(1)NSManagedObjectContext(被管理的数据上下文)

操作实际内容(操作持久层)

作用:插入数据,查询数据,删除数据

(2)NSManagedObjectModel(被管理的数据模型)

数据库所有表格或数据结构,包含各实体的定义信息

作用:添加实体的属性,建立属性之间的关系

操作方法:视图编辑器,或代码

(3)NSPersistentStoreCoordinator(持久化存储助理)

相当于数据库的连接器

作用:设置数据存储的名字,位置,存储方式,和存储时机

(4)NSManagedObject(被管理的数据记录)

相当于数据库中的表格记录

(5)NSFetchRequest(获取数据的请求)

相当于查询语句

(6)NSEntityDescription(实体结构)

相当于表格结构

(7)后缀为.xcdatamodeld的包

里面是.xcdatamodel文件,用数据模型编辑器编辑

编译后为.momd或.mom文件

6、         loadView 和 viewDidLoad 的区别

iewDidLoad此方法只有当view从nib文件初始化的时候才被调用。

loadView此方法在控制器的view为nil的时候被调用。 此方法用于以编程的方式创建view的时候用到

7、        UIViewController的生命周期及iOS程序执行顺序

当一个视图控制器被创建,并在屏幕上显示的时候。 代码的执行顺序

1、 alloc  创建对象,分配空间

2、init (initWithNibName)初始化对象,初始化数据

3、loadView  从nib载入视图 ,通常这一步不需要去干涉。除非你没有使用xib文件创建视图

4、viewDidLoad  载入完成,可以进行自定义数据以及动态创建其他控件

5、viewWillAppear  视图将出现在屏幕之前,马上这个视图就会被展现在屏幕上了

6、viewDidAppear    视图已在屏幕上渲染完成

当一个视图被移除屏幕并且销毁的时候的执行顺序,这个顺序差不多和上面的相反

1、viewWillDisappear  视图将被从屏幕上移除之前执行

2、viewDidDisappear  视图已经被从屏幕上移除,用户看不到这个视图了

3、dealloc  视图被销毁,此处需要对你在init和viewDidLoad中创建的对象进行释放

APP在运行时的调用顺序

      1)- (void)viewDidLoad

一个APP在载入时会先通过调用loadView方法或者载入IB中创建的初始界面的方法,将视图载入到内存中。然后会调用viewDidLoad方法来进行进一步的设置。只会在APP刚开始加载的时候调用一次

2) -(void)viewDidUnload; 在系统退出或者收到内存警告的时候才会被调用

3)-(void)viewWillAppear:(BOOL)animated;系统在载入所有数据后,将会在屏幕上显示视图,这时会先调用这个方法

4) -(void)viewDidAppear:(BOOL)animated;对视图进行更新。那么可以重写这个方法

5) -(void)viewWillDisappear:(BOOL)animated;在视图变换时,

当前视图在即将被移除、或者被覆盖时,会调用这个方法进行一些善后的

处理和设置

6) -(void)viewDidDisappear:(BOOL)animated;我们可以重写这个

方法,对已经消失,或者被覆盖,或者已经隐藏了的视图做一些其他操作

 

运行APP —> 载入视图 —> 调用viewDidLoad方法 —> 调用

viewWillAppear方法 —>调用viewDidAppear方法 —>正常运行 

8、        iOS的内存管理

在ObjC中每个对象内部都有一个与之对应的整数(retainCount),叫“引用计数器”,当一个对象在创建之后它的引用计数器为1,当调用这个对象的alloc、retain、new、copy方法之后引用计数器自动在原来的基础上加1(ObjC中调用一个对象的方法就是给这个对象发送一个消息),当调用这个对象的release方法之后它的引用计数器减1,如果一个对象的引用计数器为0,则系统会自动调用这个对象的dealloc方法来销毁这个对象。

内存释放的原则:谁创建、谁释放

Object-C对象生成分配空间在堆上,需要使用指针来指向其引用。

      +(id) alloc;注意这里的alloc是一个类方法,调用alloc方法之后会在内存中分配一块空间,并且引用计数会设置为1

+(id) init;调用init方法表示初始化对象

-(void) dealloc;这里注意一下dealloc不是一个类方法,而是一个实例方法。dealloc 方法用于销毁对象,当引用计数为0的时候系统会自动调用dealloc方法销毁对象

-(void) release;调用这个方法用于释放对象的引用,引用计数会-1

-(void) retain ;调用这个方法用于将引用计数+1

-(NSUInteger)retainCount;用于获取一个对象当前被多少对象拥有

2、任意写一段block代码,要求异步处理

      dispatch_async(dispatch_queue_t queue,^{});

3、UIWindow和UIView、CALayer的区别

UIWindow是UIView的子类。主要作用是:提供一个区域来显示UIView和将事件分发给UIView。一个应用基本上只有一个UIWindow

UIView是iOS系统中界面元素的基础,所有界面元素都继承自它。UIView本身是由CoreAnimation来实现的。UIView真正的绘图部分是由CALyer得类来管理的。当访问UIView的跟绘图、坐标有关的属性,如frame、bounds等,实际上内部都是在访问UIView所包含的CALayer的相关属性

UIView和CALayer的区别:

1、UIView可以响应事件,Layer不可以

   UIView的继承结构为:UIResponder:NSObject。UIResponder是用来响应事件的,所以UIView可以响应用户事件

   CALayer的继承结构为:NSObject,直接继承自NSObject所以CALayer不能响应事件

2、UIView侧重于对显示内容的管理,CALayer侧重于对内容的绘制

3、两者都有树状层级结构,View内部有SubViews,Layer内部有SubLayers,但是Layer比View多了个AnchorPoint。

4、    CALayer内部维护这三份Layer Tree,分别是presentLayer Tree动画树、modeLayer模型树、Render Tree渲染树

4、        delegate、Notification以及KVO、KVC的区别

delegate、Notification以及KVO的功能类似,都是作用于OC中对象

      的消息通信。但三者的使用场景是不同的。

A.    delegate是一种回调函数,一对一。接受者可以返回值给发送者

B.    Notification,使用Notification Center,类似广播方式,所以更适合一对多的通信;接受者无法返回值给发送者

C.    KVO,key-Value-Observing,观察者模式,适用于监听另一对象的属性的变化。一个对象能够观察另外一个对象的属性的值,并且能够发现值的变化。一对多的通信,无返回值

KVO的使用也很简单,就是简单的3步。
     

1. 注册需要观察的对象的属性

      addObserver:forKeyPath:options:context:
    

2. 实现

observeValueForKeyPath:ofObject:change:context:方法,这

个方法当观察的属性变化时会自动调用
    

      3.取消注册观察removeObserver:forKeyPath:context:

 

D.    KVC,即是指 NSKeyValueCoding,键值编码,一个非正式的Protocol,通过指定的key来访问对象的属性。而不是通过调用Setter、Getter方法访问。KVO就是基于 KVC 实现的关键技术之一

5、        继承跟类别的区别,为什么要有类别的存在?

*类别:类别是对一个功能完备的类的一种补充,就像是一个东西的主要基本功能都完成了,可以用类别为这个类添加不同的组件,使得这个类能够适应不同情况的需求。比如animal这个类,具有eat和run等方法,想给这个类添加一个bark的方法,可以用类别。

 

*继承:多个类具有相同的实例变量和方法时,考虑用继承。即子类可以继承父类的相同特性。如animal具有年龄和体重两个属性,dog也具有年龄和体重两 个属性,dog可以继承animal的这两个属性,即为继承。

共同点:都是给一个类进行扩展

区别:1.类别是对方法的扩展,不能添加成员变量。继承可以在原来父类的成员变量的基础上,添加新的成员变量

      2.类别只能添加新的方法,不能修改和删除原来的方法。继承可以增加、修改和删除方法。

      3.类别不提倡对原有的方法进行重载。继承可以通过使用super对原来方法进行重载。

     4.类别可以被继承,如果一个父类中定义了类别,那么其子类中也会继承此类别

6、        简述ARC的机制原理

如果需要持有一个对象,那么对其发送retain 。如果之后不再使用该对象,那么需要对其发送release(或者autorealse) 每一次对retain,alloc或者new的调用,需要对应一次release或autorealse调用

ARC所做的只不过是在代码编译时自动在合适的位置插入release或autorelease

7、        简单编写一个block代理?

8、        MVC是什么?有什么特性?为什么在iphone上被广泛运用?

Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写。一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。MVC被独特的发展起来用于映射传统的输入、处理和输出功能在一个逻辑的图形化用户界面的结构中

9、        委托是什么?委托的property声明用什么属性?为什么?

委托:一个对象保存另一个对象的引用,被引用的对象实现了事先确定的协议,该协议用于将引用对象中的变化通知给被引用对象。

委托和委托方双方的property声明属性都是assign而不是retain

为了避免循环引用造成的内存泄露

循环引用的问题这样理解:比如在main函数中创建了两个类的对象A和B,现在引用计数是1.现在让A和B互相引用(A有一个属性是B对象,属性说明是retain;B有一个属性是A对象,属性说明是retain),现在两个对象的引用计数都增加1,都变成了2.现在执行[Areleasw];[B release];此时创建对象的main函数已经释放了自己对对象的所有权,但是此时A和B的引用计数都还是1,因为他们互相引用了。 这使你发现A和B将无法释放,因为要想释放A必须先释放B,在B的dealloc方法中再释放A。同理,想要释放B必须先释放A,在A的dealloc方法中再释放B。所以这两个对象将一直存在内存中而不释放,这就是所谓的循环引用的问题

10、     项目使用过哪些第三方库?

11、     怎么实现tableView懒加载?

12、     编写一个singleton单例的类?

13、     开发过程中最常见的异常有哪些,列举几个?

14、      推送机制

苹果的推送服务APNs基本原理

苹果利用自己专门的推送服务器(APNs)接收来自我们自己应用服务器的需要被推送的信息,然后推送到指定的iOS设备上,然后由设备通知到我们的应用程序,设备以通知或者声音的形式通知用户有新的消息。

设备和APNS服务器之间的通讯是基于SSL协议的TCP流通讯,二者之间维持一个长连接

推送的过程经过如下步骤:

1.首先,安装了具有推送功能的应用,我们的设备在有网络的情况下会连接苹果推送服务器,连接过程中,APNS会验证device_token,连接成功后维持一个长连接;

2.Provider(我们自己的服务器)收到需要被推送的消息并结合被推送设备的device_token一起打包发送给APNS服务器;

3.APNS服务器将推送信息推送给指定device_token的设备;

4.设备收到推送消息后通知我们的应用程序并显示和提示用户(声音、弹出框)

15、     获取一台设备唯一标识的方法有哪些?

   -(NSString*) uuid {    

    CFUUIDRef puuid = CFUUIDCreate( nil );    

    CFStringRef uuidString = CFUUIDCreateString( nil, puuid

 );    

    NSString * result = (NSString *)CFStringCreateCopy( NUL

L, uuidString);    

    CFRelease(puuid);    

    CFRelease(uuidString);  

return [result autorelease];

16、     写一个委托的interface。

#import

@protocolMyDelegate;//声明

@interfaceMyClass:NSobject

{

iddelegate;

}

@end

@protocolMyDelegate//委托方法

-(void)didJobs:(NsArray*)args;

@end

17、     如何管理内存

Objective-C提供了三种内存管理方式:manualretain-release(MRR,手动管理),automaticreference counting(ARC,自动引用计数),garbagecollection(垃圾回收)。iOS不支持垃圾回收

内存管理的目的是:

1.不要释放或者覆盖还在使用的内存,这会引起程序崩溃;

2.释放不再使用的内存,防止内存泄露

猜你喜欢

转载自blog.csdn.net/m403180222/article/details/49359665
今日推荐