《IOS高级软件开发工程师80题》
*设计模式 一个功能 怎么设计
*响应链
*冒泡排序 二叉树
*内存池
基础 (1-40)
(1)assign,copy,retain;
assign:
简单赋值,不改变引用计数,一般用于非oc对象,如int等普通类型;
copy:
a:先release旧值,再copy新值,应用计数+1,内容拷贝,一般用于NSString等不可变的对象;
b:本质为复制该内存所存储的内容,重新创建一个对象赋给其相同的内容,即创建一个新对象,内容不变;
c:指针指向不同的内存区域;
retain:
a:先relase旧值,再retain新值,引用计数+1,指针拷贝, 一般用于OC中的对象;
b:最终指向同一块内存区域;
(2)strong与weak,unsafe_unretained:指针指向内存地址,内存地址存储内容
strong:强引用 ,引用计数+1;
weak: 弱引用,当指针指向的地址一旦被释放,这些指针将被赋值为nil ,防止引起野指针;
说明:a:strong与weak是arc引入的,类似于非arc下的retain与assign
b:放风筝:strong相当于风筝线,weak相当于风筝的影子
unsafe _unretained: 声明一个弱应用,但是不会自动nil化,也就是说,如果所指向的内存区域被释放了,这个指针就是一个野 指针了。
(3)类变量@private,@protected,@public,@package,声明各有什么含义?
@private:作用范围只能在自身类
@protected:作用范围在自身类和继承自己的子类 (默认)
@public:作用范围最大,可以在任何地方被访问。
@package:这个类型最常用于框架类的实例变量,同一包内能用,跨包就不能访问
(4).虚位以待?
(5)IOS本地数据存储有哪几种方式?
NSKeyedArchiver:归档形式保存数据,遵守NSCoding协议
NSUserDefaults:应用程序设置和属性,用户保存的数据
Write写入:永久保存到磁盘中
Sqlite (FMDB):FMDB中小型数据库
coredata
(6)深拷贝与浅拷贝的理解
浅拷贝:复制出来一个跟原对象相同地址的对象/只复制指向对象的指针,而不复制引用对象本身
深拷贝:复制一个跟源对象不同地址的对象,改变源对象对新对象没有影响/复制引用对象本身
总结:
浅复制好比你和你的影子,你完蛋,你的影子也完蛋
深复制好比你和你的克隆人,你完蛋,你的克隆人还活着
(13)举出5个你所熟悉的ios sdk库有哪些和第三方库有哪些?
AFWorking/WebKit/SQLite/Core Data/Address Book
(8)#import、#include和@class有什么区?
#import 系统文件,自定义文件引用 自动只导入一次 不会重复导入
#include 和 #import 几乎一样 但是他需要注意不能重复引用
@class 只是告诉系统有这个类,但是如果在实现类中用到这个类需要重新用 #import导入该类头文件
(9) 什么事序列化和反序列化,可以用来做什么?如何在oc中实现复杂对象的存储?
序列化是把对象转化成字节序列的过程 反序列化是把字节序列恢复成对象
将对象写到文件或者数据库里,并且能读取出来
遵循NSCoding协议,实现复杂对象的存储 实现该协议后可以对其进行打包或解包,转化成NSData
(10)简述应用程序按Home键进入后台时的生命周期,以及从后台回到前台时的生命周期?
将进入后台时
-(void)applicationWillResignActive:(UIApplication *)application;
-(void)applicationDidEnterBackground:(UIApplication *)application;
进入前台时
-(void)applicationDidEnterForeground:(UIApplication *)application;
-(void)applicationWillResignActive:(UIApplication *)application;
(11)viewcontroller的alloc loadView,viewDidLoad,viewWillAppear,viewWillDisAppear,viewDidAppear,viewDidDisAppear,viewDidUnload,dealloc,init分别是在什么时候调用的?
alloc申请内存时调用
loadView加载试图时调用
viewDidLoad视图已经加载后调用
ViewWillAppear视图将要渲染时调用
ViewWillDisAppear视图渲染结束时调用
ViewDidUnload视图已经加载但没有加载出来调用
dealloc销毁该视图时调用
init视图初始化时调用
(12) UIImage初始化一张图片有几种方法?简述各自的优缺点。
imgeNamed:系统会先检查系统缓存中是否有改名字的imge,如果有的话,则直接返回,如果没有,则先加载图片到缓存,然后再返回;
initWithContensOfFile:系统不会检查系统缓存,而直接从文件系统中加载并返回;
(13)怎么样实现一个单利类:避免重复创建,节省内存空间
答:在objective-c中要实现一个单例类,至少需要做以下四个步骤:
1).为单例对象实现一个静态实例,并初始化,然后设置成nil,
2).实现一个实例构造方法检查上面声明的静态实例是否为nil,如果是则新建并返回一个本类的实例,
3).重写allocWithZone方法,用来保证其他人直接使用alloc和init试图获得一个新实力的时候不产生一个新实例,
4).适当实现allocWitheZone,copyWithZone,release和autorelease。
//代码实现
static Model * model;
+(id)singleton{
if(!model){
@synchronized(self){
model = [[Model alloc]init];
}}
return model;
}
(14)分别描述类别(categories)和延展(extensions)是什么?以及两者的区别?继承和类别在实现中有何区别?为什么Category只能为对象添加方法,却不能添加成员变量?
类别:不改变原来代码的情况下往里面添加新的方法,只能添加,不能删除修改。
1.将类的实现分散到多个不同文件或多个不同框架中
2.创建私有方法的前向引用
3.向对象添加非证实协议
延展:是给类添加私有方法 只为自己类所见 所使用
1.extensions可以认为是一个私有的category
2.后者可以添加属性,且添加的方法是必须要实现的
继承:可以扩展实例变量 而类别不能/继承可以增加,修改或者删除方法,并且可以增加属性。
备注:在上线的项目更新中 用类别比继承更能维护项目的稳定性
(15)什么事懒汉模式(lazy loading)?
备懒汉模式,只在用到的时候才去初始化。也可以理解成延迟加载。
一个延时加载,避免内存过高
一个异步加载,避免线程堵塞
(16)简述KVC、KVO、NotificationCenter、Delegate?并说明它们之间的区别?
KVC(键值编码):通过字符串的名字(key)来间接访问对象属性的机制,而不是通过setter和getter。
KVO(键值观察):提供了观察某一属性变化的方法(这是一个对象与另外一个对象保持同步的一种方法),即一个对象发生变化时,观察者立马做出反应,极大的简化了代码。
NotificationCenter(消息中心):
消息的发送者告知接收者事件已经发生或者将要发生,接收者并不能反过来影响发送者的行为。
通常发送者和接收者的关系间接的多对多关系,类似于广播的形式。
任何对象可以发送通知到中心,同时任何对象可以监听中心的通知。
Delegate(代理):代理的目的是改变或者传递控制链。让别人帮助自己做某事。
说明:类A调用类B,当类B想回调类A的方法的时候,要用到delegate.多用于发送者希望接收到接受者的某个功能反馈值.
(17).简述你对UIView、UIWindow和CALayer的理解
UIView:属于UIkit.framework框架,负责渲染矩形区域的内容,为矩形区域添加动画,响应区域的触摸事
件,布局和管理一个或多个子视图
UIWindow:属于UIKit.framework框架,是一种特殊的UIView,通常在一个程序中只会有一个UIWindow,但可以手动创建多个UIWindow,同时加到程序里面。UIWindow在程序中主要起到三个作用:
1、作为容器,包含app所要显示的所有视图
2、传递触摸消息到程序中view和其他对象
3、与UIViewController协同工作,方便完成设备方向旋转的支持
CAlayer:属于QuartzCore.framework,是用来绘制内容的,对内容进行动画处理依赖与UIView来进行显示,不能处 理用户事件。UIView和CALayer是相互依赖的,UIView依赖CALayer提供内容,CALayer依赖UIView一共容器显示 绘制内容。
UIViewController:管理视图的基础,每个视图控制器都有一个自带的视图,并且负责这个视图相关的一切事务。方便管理视图中的子视图,负责model与view的通信;检测设备旋转以及内存警告
(18)ViewController 的 didReceiveMemoryWarning 是在什么时候被调用的?
当应用程序的内存使用接近系统的最大内存使用时,应用会向系统发送内存警告,程序收到内存警告时候ViewController会调用 didReceiveMemoryWarning这个方法
(18)看下面的程序,第一个nslog会输出什么?找时str的retain count 是多少?第二个和第三个呢?为什么
(19)block的使用?
(1) Block的声明
Block(闭包)是可以获取其他函数内部变量的匿名函数,其不但方便开发,并且可以大幅提高应用的执行效率。
Blo以上声明了一个名字叫做WXYTestBlock的block, 参数为一个字符串类型的name和一个int类型的age,返回值为NSString.当然你也可以声明成这样
无参数,无返回值。
(2) Block的使用
a:独立block
b:内联block
(3) Block使用外部变量
一个有趣的现象:
现在你定义了一个独立的block,并且这个block使用了外部的变量
然后这个变量又被改变了,然后你调用了这个block
注意书序:定义独立block并且使用外部变量---》外部变量改变---》调用block
这是为什么呢?
block中如果使用了外部变量,他会拷贝一份这个变量,并且这个变量是只读的。
所以外部变量改变并不影响block内部拷贝的那一份变量。
代码中的内联block是在变量改变后才使用这个变量的,所以并不影响。
如果不想让block拷贝变量,想让内部使用的变量和外部使用的变量指向同一地址的话
需要在变量前面加上__block关键字
需要说明的是,加上__block关键字之后,外部变量不再是只读的,在block内部也可以改变它的值。
(4)block循环引用的问题
首先在self类中声明一个NSString的属性
现在:你想要在block中使用self,或者使用self.myStr
如果,self的类中包含block,block中又引用了self,这样就会造成循环引用
解决方法如下
将self转化成为一个用__weak修饰的weakSelf, 就可以避免循环引用
(20).谈谈你对多线程开发的理解?ios中有几种实现多线程的方法?
好处:
1.使用线程可以把占据时间长的程序中的任务放到后台去处理
2.程序的运行速度可能加快
3.体验更加友好
缺点:
1.如果有大量的线程,会影响性能,因为操作系统需要在它们之间切换。
2.更多的线程需要更多的内存空间。
3.线程的中止需要考虑其对程序运行的影响。
实现多线程的方法:
NSOperation
NSOperation是一个抽象类,它封装了线程的细节实现,我们可以通过子类化该对象,加上NSQueue来同面向对象的思维,管理多线程程序。具体可参看这里:一个基于NSOperation的多线程网络访问的项目。
NSThread
NSThread是一个控制线程执行的对象,它不如NSOperation抽象,通过它我们可以方便的得到一个线程,并控制它。但NSThread的线程之间的并发控制,是需要我们自己来控制的,可以通过NSCondition实现。
NSThread: 主线程中执行:performSelector:OnMainThread
延时执行:performSelector:onThread:withObject:waitUntilDone:
GCD :
GCD(Grand Central Dispatch) ,对多线程,多核开发较完整的封装,在使用GCD的时候,系统会自动根据CPU使用情况进行调度线程。
自己只是创建队列queue 所有的执行都放到队列中,队列的特点是FIFO(先提交的先执行)
*队列: 串行 并行
*线程: 同步 异步
综合:
GCD: 线程管理总结
*同步执行
(1) 并发队列:不会开线程
(2)串行队列:不会开线程
*异步执行
(1)并发队列: 能开启n条线程
(2)串行队列: 开启1条线程
(19)响应链
事件响应链:UIButton - UIView - UIViewController - UIWindow - UIApplication - AppDelegate
响应者:iOS中,能够响应事件的对象都是UIResponder的子类对象。UIResponder提供了四个用户点击的回调方法,分别对应用户点击开始,移动,点击结束以及取消点击,其中只有在程序强制退出或者来电时,取消点击事件才会调用。
(20) 代理为什么使用weak?
如果使用strong,则会执行UIScrollView*scrollView=[[UIScrollview alloc] init]; scrollview.delegate=self;
(self代表控制器)
当控制器想要销毁时,控制器被强指针指着; (self被scrollview.delegate指着)
scrolview添加到视图控制器view也被强指针指着,无法销毁,那么他的delegate不会销毁;
delegate指向控制器,造成了循环引用。
把delegate变成weak; 当控制器生命周期结束时,view随之销毁,delegate也就销毁了;
(20):框架Foundation概述
1.Cocoa是创建Mac OS X 和 IOS程序的原生面相对象API,为两者应用提供了编程环境。
2.Cocoa是一个框架的集合,包含中国子框架,最重要的有Foundation和UIKit.前者是基础框架,和界面无关,包含大量常用的API;
后者是基础的UI类库。
3.所有的Mac OS X 和 IOS程序都是由大量对象构成,而这些对象的根对象都是NSObject,NSObject都在Foundation框架之中。
(21)
(40)小知识点
1.id声明的对象有什么特性?
答:id声明的对象具有运行时的特性,即可以指向任意类型的obj对象
2.如何对ios设备进行性能测试?
答: Profile-> Instruments ->Time Profiler
3.多态
答:不同对象以自己的方式响应相同的消息的能力叫做多态
4.方法和选择器有什么不同?
答:selector是一个方法的名字,method是一个组合体,包含了名字和实现。
5.在应用中可以创建多少autorelease对象,是否有限制?
答:无
6.什么时候需要程序中创建内存池?
答:界面线程维护着自己的内存池,用户自己创建的数据线程,则需要创建该线程的内存池。
7.什么是简便构造方法?
答:简便构造方法一般由CocoaTouch框架提供 如:NSNumber的+numberWithBool:
8.什么是coredata?
答:coredata是苹果提供一套数据保存框架,其基于SQlite
7.什么是谓词?
答:谓词是通过NSPredicate给定逻辑条件作为约束条件,完成对数据的筛选。
8.什么
答:简
9.什么
答:简
10.什么
//=========================//==========高级问题设置===========//===========================
冒泡算法 二叉树 数据库设计 生命周期 runtime
(41)大量数据处理
大量数据意味着需要我们关注内存占用和性能,写代码时需要记得一下规划:
1.尽可能缓存需要的数据,不相关的数据保持faults状态
2.fetch时尽可能精准,少引入不相关的数据
3.构建多context时尽量将同类managed object集中,最大限度减少合并需求
4.提升操作效率,对asynchronous fetch, batch update,batch delete等新特性尽可能利用
(42)RunLoop
一般来讲,一个线程一次只能执行一个任务,执行完成后线程就会退出。如果我们需要一个机制,让线程能随时处理事件但并不退出,通常的代码逻辑是这样的:
1
2
3
4
5
6
7
function loop() {
initialize();
do {
var message = get_next_message();
process_message(message);
} while (message != quit);
}
这种模型通常被称作Event Loop。 Event Loop 在很多系统和框架里都有实现,比如 Node.js 的事件处理,比如 Windows 程序的消息循环,再比如 OSX/iOS 里的 RunLoop。实现这种模型的关键点在于:如何管理事件/消息,如何让线程在没有处理消息时休眠以避免资源占用、在有消息到来时立刻被唤醒。
所以,RunLoop 实际上就是一个对象,这个对象管理了其需要处理的事件和消息,并提供了一个入口函数来执行上面 Event Loop 的逻辑。线程执行了这个函数后,就会一直处于这个函数内部 "接受消息->等待->处理" 的循环中,直到这个循环结束(比如传入 quit 的消息),函数返回。
OSX/iOS 系统中,提供了两个这样的对象:NSRunLoop 和 CFRunLoopRef。
CFRunLoopRef 是在 CoreFoundation 框架内的,它提供了纯 C 函数的 API,所有这些 API 都是线程安全的。
NSRunLoop 是基于 CFRunLoopRef 的封装,提供了面向对象的 API,但是这些 API 不是线程安全的。
CFRunLoopRef 的代码是开源的,你可以在这里http://opensource.apple.com/tarballs/CF/CF-855.17.tar.gz下载到整个 CoreFoundation 的源码。为了方便跟踪和查看,你可以新建一个 Xcode 工程,把这堆源码拖进去看。
(43)RunTime
1.runtime实现的机制是什么,怎么用,一般用来干嘛?
答:runtime是一套比较底层的纯c语言API,属于1个C语言库,包含了很多底层的C语言API.
2.runtime用来干什么呢?用在哪些地方呢?怎么用呢?
答: 1.在程序运行过程中,动态创建一个类(比如kvo的底层实现)
2. 在程序运行过程中,动态地为某个类添加属性/方法,修改属性/方法
3. 遍历一个类的所有成员变量(属性)/所有方法
(44) Socket: 熟悉TCP/IP协议族,定义了主机如何连入因特网及数据束河在他们之间传输
应用层: HTTP SNMP FTP NDS
传输层: TCP UDP
网络层: IP
1.Socket描述了一个IP, 端口对。它简化了程序的操作,知道对方的IP以及PORT就可以给对方发送消息,再由服务器来处理发送的这些消息。所以,socket一定包含了通信的双发,即客户端(Client)与服务器(server).
a: 服务端利用socket监听端口
b: 客户端发起连接
c: 服务端返回信息,建立连接,开始通信
d: 客户端,服务端断开连接
2.套接字(socket)是通信的基石,是支持TCP/IP协议的网络通信的基本单元;
应用层通过传输层进行数据通信时,TCP会遇到同时为多个应用程序进程提供并发服务的进程。
多个TCP连接或者多个应用程序进程可能需要通过同一个TCP协议端口传输数据,为了区分不同的应用程序进程或连接
许多计算机系统为应用程序与TCP/IP协议交互提供了套接字(socket)接口,应用层和传输层通过socket接口,区分来自不同应用程序或者网络连接的通信,实现数据传输的并发服务;
3. 建立socket连接至少需要一对套接字,其中一个运行于客户端(Clientsocket),另一个运行于服务器端(Serversocket);
套接字之间的连接分为三个步骤:服务器监听 客户端请求 连接确认。
4.创建Socket连接时,可以指定使用的传输层协议,Socket可以支持不同的传输层协议(TCP或UDP),当使用TCP协议进行连接时,该Socket连接就是一个TCP连接。
(45) :写一个标准宏MIN,这个宏输入两个参数并返回较小的一个?
#define MIN(X,Y) ((X)>(Y)?(Y):(X))
扩展:在定义宏的时候需要注意哪些问题?
宏全部大写 写在#import 下 @interface上 结尾无分号
(46).假设有一个字符串aabcad,请写一段程序,去掉字符串中不相邻的重复字符串,即上述字符串处理之后的输出结果为:aabcd
NSMutableString * str = [[NSMutableString alloc]initWithFormat;@“aabcad”];
for (int i = 0 ,i < str.length - 1 ;i++){
unsigned char a = [str characterAtIndex:i];
for (int j = i + 1 ,j < str.length ,j++){
unsigned char b = [str characterAtIndex:j];
if (a == b ){
if (j == i + 1){
}else{
[str deleteCharactersInRange:NSMakeRange(j, 1)];
}
}
}
}
NSLog(@“%@”,str);
(47)谓词
(48)自动化测试
网友评论