iOS基础面试题(一)
项目流程:
项目的具体流程,技术点在流程中哪些地方使用。(这个问题的问到的几率很高!)
项目的具体流程:
(1)可行性分析:这个一般都是做战略的专家来做的,他们更加有市场的前瞻性,俗话说就是看的更远一些,搞市场分析、调研,看看我们的想法到底是否可行,可行性有多大,可能会遇到的问题,我们的优势在哪里,可以利用的资源有哪些,需要引进那些资源,有多少对手,他们都进行到了什么程度等等。
这个阶段的文档成果是:可行性分析报告等
(2)需求分析:这个已经开始具体操作,经过可行性分析,我们有机会,可以进入这个领域。这时候,需要领域专家参与进来,架构师也要参与进来,还有就是需求分析的专业人士,和最少一名文档员,用来记录开发讨论的结果并形成文档。
工作就是分解项目的需求,到底要做些什么,要实现什么功能,就是功能的范围和功能的细节,主要还是业务方面的梳理。
这个阶段的文档成果是:需求分析说明书等
(3)概要设计:经过前面的需求分析,形成了需求分析说明书。这个阶段应该是业务建模,形成业务用例,进一步形成业务用例。这个阶段是分解需求,可以使用数据库建模工具,或者是UML建模工具来辅助一下。
这个阶段的文档成果是:概要设计说明书、业务用例文档等
(4)详细设计:有了概要设计,有了模型,可以定义出数据库模型,甚至是可以定义数据库的字段,然后可以让高级程序员来辅助架构师进行架构设计,普通程序员先写实现的技术用例。或者让他们先看看业务用例,熟悉一下业务流程和项目的目标。
这个阶段的文档成果是:概要设计说明书、技术用例文档等
(5)具体开发:这个阶段就是具体的代码编写了,考验程序员的基本功的时候到了。
关于开发的分工的话,我趋向于分层来分工,这样有以下几个好处:
不用每个人从数据访问写到界面表现,可以集中精力,精益求精,便于后期优化
中间层可拔插,可替换,可以优化,增加可扩展性
可以享受ORM带来的一些好处
增加可测试性,做得好,甚至可以测试外包
这个阶段的文档成果是:接口文档,关键算法文档等
可能会有人说,怎么没有测试呢?其实测试时贯穿整个流程的,在需求分析的时候,可以让他们熟悉业务,出来需求之后,他们就可以编写一些手动测试的测试用例,后面产品出来就可以测试了。开发人员的开发的时候,他们就要进行自动化测试的准备。
还有就是一定要形成文档,每个阶段都会有开会,开会大家都有讨论,都需要有结论,有纸质的文档进行保存,可以买录音笔,先录下来,然后整理成文档,因为每个阶段都是后面阶段的基础,如果基础出了问题,后面都会是有问题的,所以后面备查。
1. Object-c的类可以多重继承么?可以实现多个接口么?Category是什么?重写一个类的方式用继承好还是分类好?为什么?
Object-c的类不可以多重继承;可以实现多个协议,通过实现多个协议可以完成C++的多重继承;Category是类别,一般情况用分类好,用Category去重写类的方法,仅对本Category有效,不会影响到其他类与原有类的关系。
2.#import 跟#include 又什么区别,@class呢, #import<> 跟 #import”"又什么区别?
#import是Objective-C导入头文件的关键字,#include是C/C++导入头文件的关键字,使用#import头文件会自动只导入一次,不会重复导入,相当于#include和#pragma once;@class告诉编译器某个类的声明,当执行时,才去查看类的实现文件,可以解决头文件的相互包含;#import<>用来包含系统的头文件,#import””用来包含用户头文件。
3. 属性readwrite,readonly,assign,retain,copy,nonatomic 各是什么作用,在那种情况下用?
readwrite 是可读可写特性;需要生成getter方法和setter方法时
readonly 是只读特性 只会生成getter方法 不会生成setter方法 ;不希望属性在类外改变
assign 是赋值特性,setter方法将传入参数赋值给实例变量;仅设置变量时;
retain 表示持有特性,setter方法将传入参数先保留,再赋值,传入参数的retaincount会+1;
copy 表示赋值特性,setter方法将传入对象复制一份;需要完全一份新的变量时。
nonatomic 非原子操作,决定编译器生成的setter getter是否是原子操作,atomic表示多线程安全,一般使用nonatomic
4.写一个setter方法用于完成@property (nonatomic,retain)NSString *name,写一个setter方法用于完成@property(nonatomic,copy)NSString *name
[cpp] view plaincopyprint?
- (void) setName:(NSString*) str
{
[str retain];
[name release];
name = str;
}
- (void)setName:(NSString *)str
{
id t = [str copy];
[name release];
name = t;
}
5.对于语句NSString*obj = [[NSData alloc] init]; obj在编译时和运行时分别时什么类型的对象?
编译时是NSString的类型;运行时是NSData类型的对象
6.常见的object-c的数据类型有那些, 和C的基本数据类型有什么区别?如:NSInteger和int
object-c的数据类型有NSString,NSNumber,NSArray,NSMutableArray,NSData等等,这些都是class,创建后便是对象,而C语言的基本数据类型int,只是一定字节的内存空间,用于存放数值;NSInteger是基本数据类型,并不是NSNumber的子类,当然也不是NSObject的子类。NSInteger是基本数据类型Int或者Long的别名(NSInteger的定义typedef long NSInteger),它的区别在于,NSInteger会根据系统是32位还是64位来决定是本身是int还是Long。
7.id 声明的对象有什么特性?
id 声明的对象具有运行时的特性,即可以指向任意类型的objcetive-c的对象;
8.Objective-C如何对内存管理的,说说你的看法和解决方法?
Objective-C的内存管理主要有三种方式ARC(自动内存计数)、手动内存计数、内存池。
9.内存管理的几条原则时什么?按照默认法则.那些关键字生成的对象
需要手动释放?在和property结合的时候怎样有效的避免内存泄露?
谁申请,谁释放
遵循Cocoa Touch的使用原则;
内存管理主要要避免“过早释放”和“内存泄漏”,对于“过早释放”需要注意@property设置特性时,一定要用对特性关键字,对于“内存泄漏”,一定要申请了要负责释放,要细心。
关键字alloc 或new 生成的对象需要手动释放;
设置正确的property属性,对于retain需要在合适的地方释放,
10.如何对iOS设备进行性能测试?
Profile-> Instruments ->Time Profiler
11.看下面的程序,第一个NSLog会输出什么?这时str的retainCount是多少?第二个和第三个呢? 为什么?
[cpp] view plaincopyprint?
=======================================================
NSMutableArray* ary = [[NSMutableArray array] retain];
NSString *str = [NSString stringWithFormat:@"test"];
[strretain];
[aryaddObject:str];
NSLog(@"%@%d",str,[str retainCount]);
[strretain];
[strrelease];
[strrelease];
NSLog(@"%@%d",str,[str retainCount]);
[aryremoveAllObjects];
NSLog(@"%@%d",str,[str retainCount]);
=======================================================
str的retainCount创建+1,retain+1,加入数组自动+1
3
retain+1,release-1,release-1
2
数组删除所有对象,所有数组内的对象自动-1
1
12. Object C中创建线程的方法是什么?如果在主线程中执行代码,方法是什么?如果想延时执行代码、方法又是什么?
线程创建有三种方法:使用NSThread创建、使用GCD的dispatch、使用子类化的NSOperation,然后将其加入NSOperationQueue;在主线程执行代码,方法是performSelectorOnMainThread,如果想延时执行代码可以用performSelector:onThread:withObject:waitUntilDone:
13.描述一下iOS SDK中如何实现MVC的开发模式
MVC是模型、试图、控制开发模式,对于iOS SDK,所有的View都是视图层的,它应该独立于模型层,由视图控制层来控制。所有的用户数据都是模型层,它应该独立于视图。所有的ViewController都是控制层,由它负责控制视图,访问模型数据。
iOS基础面试题(二)
1.Difference between shallow copy and deep copy?
浅复制和深复制的区别?
答案:浅层复制:只复制指向对象的指针,而不复制引用对象本身。
深层复制:复制引用对象本身。
意思就是说我有个A对象,复制一份后得到A_copy对象后,对于浅复制来说,A和A_copy指向的是同一个内存资源,复制的只不过是是一个指针,对象本身资源
还是只有一份,那如果我们对A_copy执行了修改操作,那么发现A引用的对象同样被修改,这其实违背了我们复制拷贝的一个思想。深复制就好理解了,内存中存在了
两份独立对象本身。
用网上一哥们通俗的话将就是:
浅复制好比你和你的影子,你完蛋,你的影子也完蛋
深复制好比你和你的克隆人,你完蛋,你的克隆人还活着。
2.What is advantage of categories? What is difference between implementing a category and inheritance?
类别的作用?继承和类别在实现中有何区别?
答案:category 可以在不获悉,不改变原来代码的情况下往里面添加新的方法,只能添加,不能删除修改。
并且如果类别和原来类中的方法产生名称冲突,则类别将覆盖原来的方法,因为类别具有更高的优先级。
类别主要有3个作用:
(1)将类的实现分散到多个不同文件或多个不同框架中。
(2)创建对私有方法的前向引用。
(3)向对象添加非正式协议。
继承可以增加,修改或者删除方法,并且可以增加属性。
3.Difference between categories and extensions?
类别和类扩展的区别。
答案:category和extensions的不同在于 后者可以添加属性。另外后者添加的方法是必须要实现的。
extensions可以认为是一个私有的Category。
4.Difference between protocol in objective c and interfaces in java?
oc中的协议和java中的接口概念有何不同?
答案:OC中的代理有2层含义,官方定义为 formal和informal protocol。前者和Java接口一样。
informal protocol中的方法属于设计模式考虑范畴,不是必须实现的,但是如果有实现,就会改变类的属性。
其实关于正式协议,类别和非正式协议我很早前学习的时候大致看过,也写在了学习教程里
“非正式协议概念其实就是类别的另一种表达方式“这里有一些你可能希望实现的方法,你可以使用他们更好的完成工作”。
这个意思是,这些是可选的。比如我门要一个更好的方法,我们就会申明一个这样的类别去实现。然后你在后期可以直接使用这些更好的方法。
这么看,总觉得类别这玩意儿有点像协议的可选协议。"
现在来看,其实protocal已经开始对两者都统一和规范起来操作,因为资料中说“非正式协议使用interface修饰“,
现在我们看到协议中两个修饰词:“必须实现(@requied)”和“可选实现(@optional)”。
5.What are KVO and KVC?
Key-Value Observing
Key value coding
答案:kvc:键 - 值编码是一种间接访问对象的属性使用字符串来标识属性,而不是通过调用存取方法,直接或通过实例变量访问的机制。
很多情况下可以简化程序代码。apple文档其实给了一个很好的例子。
kvo:键值观察机制,他提供了观察某一属性变化的方法,极大的简化了代码。
具体用看到嗯哼用到过的一个地方是对于按钮点击变化状态的的监控。
比如我自定义的一个button
[cpp]
[self addObserver:self forKeyPath:@"highlighted" options:0 context:nil];
#pragma mark KVO
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([keyPath isEqualToString:@"highlighted"] ) {
[self setNeedsDisplay];
}
}
对于系统是根据keypath去取的到相应的值发生改变,理论上来说是和kvc机制的道理是一样的。
对于kvc机制如何通过key寻找到value:
“当通过KVC调用对象时,比如:[self valueForKey:@”someKey”]时,程序会自动试图通过几种不同的方式解析这个调用。首先查找对象是否带有 someKey 这个方法,如果没找到,会继续查找对象是否带有someKey这个实例变量(iVar),如果还没有找到,程序会继续试图调用 -(id) valueForUndefinedKey:这个方法。如果这个方法还是没有被实现的话,程序会抛出一个NSUndefinedKeyException异常错误。
(cocoachina.com注:Key-Value Coding查找方法的时候,不仅仅会查找someKey这个方法,还会查找getsomeKey这个方法,前面加一个get,或者_someKey以及_getsomeKey这几种形式。同时,查找实例变量的时候也会不仅仅查找someKey这个变量,也会查找_someKey这个变量是否存在。)
设计valueForUndefinedKey:方法的主要目的是当你使用-(id)valueForKey方法从对象中请求值时,对象能够在错误发生前,有最后的机会响应这个请求。这样做有很多好处,下面的两个例子说明了这样做的好处。“
来至cocoa,这个说法应该挺有道理。
因为我们知道button却是存在一个highlighted实例变量.因此为何上面我们只是add一个相关的keypath就行了,
可以按照kvc查找的逻辑理解,就说的过去了。
What is purpose of delegates?代理的作用?
答案:代理的目的是改变或传递控制链。允许一个类在某些特定时刻通知到其他类,而不需要获取到那些类的指针。可以减少框架复杂度。
另外一点,代理可以理解为java中的回调监听机制的一种类似。
7.What are mutable and immutable types in Objective C?oc中可修改和不可以修改类型。
答案:可修改不可修改的集合类。这个我个人简单理解就是可动态添加修改和不可动态添加修改一样。
比如NSArray和NSMutableArray。前者在初始化后的内存控件就是固定不可变的,后者可以添加等,可以动态申请新的内存空间。
8.When we call objective c is runtime language what does it mean?
我们说的oc是动态运行时语言是什么意思?
答案:多态。 主要是将数据类型的确定由编译时,推迟到了运行时。
这个问题其实浅涉及到两个概念,运行时和多态。
简单来说,运行时机制使我们直到运行时才去决定一个对象的类别,以及调用该类别对象指定方法。
多态:不同对象以自己的方式响应相同的消息的能力叫做多态。意思就是假设生物类(life)都用有一个相同的方法-eat;
那人类属于生物,猪也属于生物,都继承了life后,实现各自的eat,但是调用是我们只需调用各自的eat方法。
也就是不同的对象以自己的方式响应了相同的消息(响应了eat这个选择器)。
因此也可以说,运行时机制是多态的基础?~~~
9.what is difference between NSNotification and protocol?
通知和协议的不同之处?
答案:协议有控制链(has-a)的关系,通知没有。
首先我一开始也不太明白,什么叫控制链(专业术语了~)。但是简单分析下通知和代理的行为模式,我们大致可以有自己的理解
简单来说,通知的话,它可以一对多,一条消息可以发送给多个消息接受者。
代理按我们的理解,到不是直接说不能一对多,比如我们知道的明星经济代理人,很多时候一个经济人负责好几个明星的事务。
只是对于不同明星间,代理的事物对象都是不一样的,一一对应,不可能说明天要处理A明星要一个发布会,代理人发出处理发布会的消息后,别称B的
发布会了。但是通知就不一样,他只关心发出通知,而不关心多少接收到感兴趣要处理。
因此控制链(has-a从英语单词大致可以看出,单一拥有和可控制的对应
10、Polymorphism?关于多态性
答案:多态,子类指针可以赋值给父类。这个题目其实可以出到一切面向对象语言中,
因此关于多态,继承和封装基本最好都有个自我意识的理解,也并非一定要把书上资料上写的能背出来。
11.What is responder chain?
说说响应链
答案: 事件响应链。包括点击事件,画面刷新事件等。在视图栈内从上至下,或者从下之上传播。
可以说点事件的分发,传递以及处理。具体可以去看下touch事件这块。因为问的太抽象化了
严重怀疑题目出到越后面就越笼统。
12.Difference between frame and bounds?
frame和bounds有什么不同?
答案:frame指的是:该view在父view坐标系统中的位置和大小。(参照点是父亲的坐标系统)
bounds指的是:该view在本身坐标系统中 的位置和大小。(参照点是本身坐标系统)
13.Difference between method and selector?方法和选择器有何不同?
答案:selector是一个方法的名字,method是一个组合体,包含了名字和实现.
详情可以看apple文档。
14.Is there any garbage collection mechanism in Objective C.?
OC的垃圾回收机制?
答案: OC2.0有Garbage collection,但是iOS平台不提供。
一般我们了解的objective-c对于内存管理都是手动操作的,但是也有自动释放池。
但是差了大部分资料,貌似不要和arc机制搞混就好了。
求更多~~
15.NSOperation queue?
答案:存放NSOperation的集合类。
操作和操作队列,基本可以看成java中的线程和线程池的概念。用于处理ios多线程开发的问题。
网上部分资料提到一点是,虽然是queue,但是却并不是带有队列的概念,放入的操作并非是按照严格的先进现出。
这边又有个疑点是,对于队列来说,先进先出的概念是Afunc添加进队列,Bfunc紧跟着也进入队列,Afunc先执行这个是必然的,
但是Bfunc是等Afunc完全操作完以后,B才开始启动并且执行,因此队列的概念离乱上有点违背了多线程处理这个概念。
但是转念一想其实可以参考银行的取票和叫号系统。
因此对于A比B先排队取票但是B率先执行完操作,我们亦然可以感性认为这还是一个队列。
但是后来看到一票关于这操作队列话题的文章,其中有一句提到
“因为两个操作提交的时间间隔很近,线程池中的线程,谁先启动是不定的。”
瞬间觉得这个queue名字有点忽悠人了,还不如pool~
16、What is lazy loading?
答案:懒汉模式,只在用到的时候才去初始化。
也可以理解成延时加载。
我觉得最好也最简单的一个列子就是tableView中图片的加载显示了。
一个延时载,避免内存过高,一个异步加载,避免线程堵塞。
17.Can we use two tableview controllers on one viewcontroller?
是否在一个视图控制器中嵌入两个tableview控制器?
答案:一个视图控制只提供了一个View视图,理论上一个tableViewController也不能放,
只能说可以嵌入一个tableview视图。当然,题目本身也有歧义,如果不是我们定性思维认为的UIViewController,
而是宏观的表示视图控制者,那我们倒是可以把其看成一个视图控制者,它可以控制多个视图控制器,比如TabbarController那样的感觉。
18.Can we use one tableview with two different datasources? How you will achieve this?
一个tableView是否可以关联两个不同的数据源?你会怎么处理?
答案:首先我们从代码来看,数据源如何关联上的,其实是在数据源关联的代理方法里实现的。
因此我们并不关心如何去关联他,他怎么关联上,方法只是让我返回根据自己的需要去设置如相关的数据源。
因此,我觉得可以设置多个数据源啊,但是有个问题是,你这是想干嘛呢?想让列表如何显示,不同的数据源分区块显示?
iOS基础面试题(三)
1.When to use NSMutableArray and when to use NSArray?
什么时候使用NSMutableArray,什么时候使用NSArray?
答案:当数组在程序运行时,需要不断变化的,使用NSMutableArray,当数组在初始化后,便不再改变的,使用NSArray。需要指出的是,使用NSArray只表明的是该数组在运行时不发生改变,即不能往NSAarry的数组里新增和删除元素,但不表明其数组內的元素的内容不能发生改变。NSArray是线程安全的,NSMutableArray不是线程安全的,多线程使用到NSMutableArray需要注意。
2.Give us example of what are delegate methods and what are data source methods of uitableview.
给出委托方法的实例,并且说出UITableVIew的Data Source方法
答案:CocoaTouch框架中用到了大量委托,其中UITableViewDelegate就是委托机制的典型应用,是一个典型的使用委托来实现适配器模式,其中UITableViewDelegate协议是目标,tableview是适配器,实现UITableViewDelegate协议,并将自身设置为talbeview的delegate的对象,是被适配器,一般情况下该对象是UITableViewController。
UITableVIew的Data Source方法有- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
3、.If we don’t create any autorelease pool in our application then is there any autorelease pool already provided to us?
如果我们不创建内存池,是否有内存池提供给我们?
答案:界面线程维护着自己的内存池,用户自己创建的数据线程,则需要创建该线程的内存池
4、.When you will create an autorelease pool in your application?
什么时候需要在程序中创建内存池?
答案:用户自己创建的数据线程,则需要创建该线程的内存池
5、.What are commonly used NSObject class methods?
类NSObject的那些方法经常被使用?
答案:NSObject是Objetive-C的基类,其由NSObject类及一系列协议构成。
其中类方法alloc、class、 description 对象方法init、dealloc、– performSelector:withObject:afterDelay:等经常被使用
6、What is convenience constructor?什么是简便构造方法?
答案:简便构造方法一般由CocoaTouch框架提供,如NSNumber的 + numberWithBool: + numberWithChar: + numberWithDouble: + numberWithFloat: + numberWithInt:
Foundation下大部分类均有简便构造方法,我们可以通过简便构造方法,获得系统给我们创建好的对象,并且不需要手动释放。
7、How to design universal application in Xcode?如何使用Xcode设计通用应用?
答案:使用MVC模式设计应用,其中Model层完成脱离界面,即在Model层,其是可运行在任何设备上,在controller层,根据iPhone与iPad(独有UISplitViewController)的不同特点选择不同的viewController对象。在View层,可根据现实要求,来设计,其中以xib文件设计时,其设置其为universal。
8、在Objetive-C什么时原子关键字
答案:atomic,nonatomic见iOS面试题(一)
9、What are UIView animations?
UIView的动画效果有那些?
答案:有很多,如 UIViewAnimationOptionCurveEaseInOut UIViewAnimationOptionCurveEaseIn UIViewAnimationOptionCurveEaseOut UIViewAnimationOptionTransitionFlipFromLeft UIViewAnimationOptionTransitionFlipFromRight UIViewAnimationOptionTransitionCurlUpUIViewAnimationOptionTransitionCurlDown
如何使用可见该博文
11、.How can you store data in iPhone applications?在iPhone应用中如何保存数据?
答案:有以下几种保存机制:
1.通过web服务,保存在服务器上
2.通过NSCoder固化机制,将对象保存在文件中
3.通过SQlite或CoreData保存在文件数据库中
12、What is coredata?什么是coredata?
答案:coredata框架是apple提供的一套通用自动的解决方案,包括了对象生存周期、对象关系图、持久化机制。
补充答案:上面是翻译的,按我个人理解coredata提供一种一机制,让我们可以方便的把内存中对象,及对象间的关系,映射到coredata,然后由它为我们持久化数据。相比普通的文件数据库SQlite,它的功能更强大,不需要我们先将对象数据format成SQL语句,存入数据库,再用select语句读出,而现在是从内存到coredata的数据管理,我们只需管理coredata的managed对象。
13、What is NSManagedObject model?什么是NSManagedObject模型?
答案:NSManagedObject是NSObject的子类 ,也是coredata的重要组成部分,它是一个通用的类,实现了core data 模型层所需的基本功能,用户可通过子类化NSManagedObject,建立自己的数据模型。
14、.What is NSManagedobjectContext?什么是NSManagedobjectContext?
答案:NSManagedobjectContext对象负责应用和数据库之间的交互。
15、.What is predicate?什么是谓词?
答案:谓词是通过NSPredicate,是通过给定的逻辑条件作为约束条件,完成对数据的筛选。
predicate = [NSPredicate predicateWithFormat:@"customerID == %d",n];
a = [customers filteredArrayUsingPredicate:predicate];
16、.What kind of persistence store we can use with coredata?
coredata有哪几种持久化存储机制?
答案:coredatat提供以下几种存储机制:XML(iOS系统不支持),自动存储,SQLite,内存存储。
补充说明:这个问题问的是,coredate框架的存储机制,平时使用coredata时,更多关注的是managed的对象,这里是coerdata框架的存储实现细节。BTW: 其他常用的持久化存储方法 :存入到文件、 存入到NSUserDefaults(系统plist文件中)。
iOS基础面试题(四)
iOS进阶面试题----Block部分
1 谈谈对Block 的理解?并写出一个使用Block执行UIVew动画?
答案:Block是可以获取其他函数局部变量的匿名函数,其不但方便开发,并且可以大幅提高应用的执行效率(多核心CPU可直接处理Block指令)
[UIView transitionWithView:self.view
duration:0.2
options:UIViewAnimationOptionTransitionFlipFromLeft
animations:^{ [[blueViewController view] removeFromSuperview]; [[self view] insertSubview:yellowViewController.view atIndex:0]; }
completion:NULL];
2 写出上面代码的Block的定义。
答案:typedef void(^animations) (void);typedef void(^completion) (BOOL finished);
3 试着使用+ beginAnimations:context:以及上述Block的定义,写出一个可以完成
+ (void)transitionWithView:(UIView *)view duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion NS_AVAILABLE_IOS(4_0);操作的函数执行部分
网络部分
4、做过的项目是否涉及网络访问功能,使用什么对象完成网络功能?
答案:ASIHTTPRequest与NSURLConnection
5、 简单介绍下NSURLConnection类及+ sendSynchronousRequest:returningResponse:error:与– initWithRequest:delegate:两个方法的区别?
答案: NSURLConnection主要用于网络访问,其中+ sendSynchronousRequest:returningResponse:error:是同步访问数据,即当前线程会阻塞,并等待request的返回的response,而– initWithRequest:delegate:使用的是异步加载,当其完成网络访问后,会通过delegate回到主线程,并其委托的对象。
iOS进阶面试题----多线程
1、 什么 是多线程
多线程是个复杂的概念,按字面意思是同步完成多项任务,提高了资源的使用效率,从硬件、操作系统、应用软件不同的角度去看,多线程被赋予不同的内涵,对于硬件,现在市面上多数的CPU都是多核的,多核的CPU运算多线程更为出色;从操作系统角度,是多任务,现在用的主流操作系统都是多任务的,可以一边听歌、一边写博客;对于应用来说,多线程可以让应用有更快的回应,可以在网络下载时,同时响应用户的触摸操作。在iOS应用中,对多线程最初的理解,就是并发,它的含义是原来先做烧水,再摘菜,再炒菜的工作,会变成烧水的同时去摘菜,最后去炒菜。
2、 iOS 中的多线程
iOS中的多线程,是Cocoa框架下的多线程,通过Cocoa的封装,可以让我们更为方便的使用线程,做过C++的同学可能会对线程有更多的理解,比如线程的创立,信号量、共享变量有认识,Cocoa框架下会方便很多,它对线程做了封装,有些封装,可以让我们创建的对象,本身便拥有线程,也就是线程的对象化抽象,从而减少我们的工程,提供程序的健壮性。
GCD是(Grand Central Dispatch)的缩写 ,从系统级别提供的一个易用地多线程类库,具有运行时的特点,能充分利用多核心硬件。GCD的API接口为C语言的函数,函数参数中多数有Block,关于Block的使用参看这里,为我们提供强大的“接口”,对于GCD的使用参见本文
3、NSOperation与Queue
NSOperation是一个抽象类,它封装了线程的细节实现,我们可以通过子类化该对象,加上NSQueue来同面向对象的思维,管理多线程程序。具体可参看这里:一个基于NSOperation的多线程网络访问的项目。
4、NSThread
NSThread是一个控制线程执行的对象,它不如NSOperation抽象,通过它我们可以方便的得到一个线程,并控制它。但NSThread的线程之间的并发控制,是需要我们自己来控制的,可以通过NSCondition实现。
参看
iOS多线程编程之NSThread的使用
5、其他多线程
在Cocoa的框架下,通知、Timer和异步函数等都有使用多线程,(待补充).
6、iOS多线程常见面试题
在项目什么时候选择使用GCD,什么时候选择NSOperation?
项目中使用NSOperation的优点是NSOperation是对线程的高度抽象,在项目中使用它,会使项目的程序结构更好,子类化NSOperation的设计思路,是具有面向对象的优点(复用、封装),使得实现是多线程支持,而接口简单,建议在复杂项目中使用。
项目中使用GCD的优点是GCD本身非常简单、易用,对于不复杂的多线程操作,会节省代码量,而Block参数的使用,会是代码更为易读,建议在简单项目中使用。
7、你使用过Objective-C的运行时编程(Runtime Programming)么?如果使用过,你用它做了什么?你还能记得你所使用的相关的头文件或者某些方法的名称吗?
Objecitve-C的重要特性是Runtime(运行时),在#import
```objective-c
Method method1 = class_getInstanceMethod(cls, sel1);
Method method2 = class_getInstanceMethod(cls, sel2);
method_exchangeImplementations(method1, method2);
```
代码交换两个方法,在写unit test时使用到。
8、. 你实现过多线程的Core Data么?NSPersistentStoreCoordinator,NSManagedObjectContext和NSManagedObject中的哪些需要在线程中创建或者传递?你是用什么样的策略来实现的?
没实现过多线程的CoreData(待实践)
3. Core开头的系列的内容。是否使用过CoreAnimation和CoreGraphics。UI框架和CA,CG框架的联系是什么?分别用CA和CG做过些什么动画或者图像上的内容。(有需要的话还可以涉及Quartz的一些内容)
UI框架的底层有CoreAnimation,CoreAnimation的底层有CoreGraphics。
UIKit |
------------ |
Core Animation |
Core Graphics |
Graphics Hardware|
使用CA做过menu菜单的展开收起(太逊了)
9、. 是否使用过CoreText或者CoreImage等?如果使用过,请谈谈你使用CoreText或者CoreImage的体验。
CoreText可以解决复杂文字内容排版问题。CoreImage可以处理图片,为其添加各种效果。体验是很强大,挺复杂的。
10、. NSNotification和KVO的区别和用法是什么?什么时候应该使用通知,什么时候应该使用KVO,它们的实现上有什么区别吗?如果用protocol和delegate(或者delegate的Array)来实现类似的功能可能吗?如果可能,会有什么潜在的问题?如果不能,为什么?(面试几率高)
NSNotification是通知模式在iOS的实现,KVO的全称是键值观察(Key-value observing),其是基于KVC(key-value coding)的,KVC是一个通过属性名访问属性变量的机制。例如将Module层的变化,通知到多个Controller对象时,可以使用NSNotification;如果是只需要观察某个对象的某个属性,可以使用KVO。
对于委托模式,在设计模式中是对象适配器模式,其是delegate是指向某个对象的,这是一对一的关系,而在通知模式中,往往是一对多的关系。委托模式,从技术上可以现在改变delegate指向的对象,但不建议这样做,会让人迷惑,如果一个delegate对象不断改变,指向不同的对象。
11、 你用过NSOperationQueue么?如果用过或者了解的话,你为什么要使用NSOperationQueue,实现了什么?请描述它和GCD的区别和类似的地方(提示:可以从两者的实现机制和适用范围来描述)。
使用NSOperationQueue用来管理子类化的NSOperation对象,控制其线程并发数目。GCD和NSOperation都可以实现对线程的管理,区别是 NSOperation和NSOperationQueue是多线程的面向对象抽象。项目中使用NSOperation的优点是NSOperation是对线程的高度抽象,在项目中使用它,会使项目的程序结构更好,子类化NSOperation的设计思路,是具有面向对象的优点(复用、封装),使得实现是多线程支持,而接口简单,建议在复杂项目中使用。
项目中使用GCD的优点是GCD本身非常简单、易用,对于不复杂的多线程操作,会节省代码量,而Block参数的使用,会是代码更为易读,建议在简单项目中使用。
更详细的答案见我的这篇文章
12、既然提到GCD,那么问一下在使用GCD以及block时要注意些什么?它们两是一回事儿么?block在ARC中和传统的MRC中的行为和用法有没有什么区别,需要注意些什么?
使用block是要注意,若将block做函数参数时,需要把它放到最后,GCD是Grand Central Dispatch,是一个对线程开源类库,而Block是闭包,是能够读取其他函数内部变量的函数。更详细的答案见我的这篇文章
13、您是否做过异步的网络处理和通讯方面的工作?如果有,能具体介绍一些实现策略么?
使用NSOperation发送异步网络请求,使用NSOperationQueue管理线程数目及优先级,底层是用NSURLConnetion,详细可见开源框架[LWConnetion](https://github.com/xunyn/LWConnetionDemo)。
14、 对于Objective-C,你认为它最大的优点和最大的不足是什么?对于不足之处,现在有没有可用的方法绕过这些不足来实现需求。如果可以的话,你有没有考虑或者实践过重新实现OC的一些功能,如果有,具体会如何做?
最大的优点是它的运行时特性,不足是没有命名空间,对于命名冲突,可以使用长命名法或特殊前缀解决,如果是引入的第三方库之间的命名冲突,可以使用link命令及flag解决冲突。
15、你实现过一个框架或者库以供别人使用么?如果有,请谈一谈构建框架或者库时候的经验;如果没有,请设想和设计框架的public的API,并指出大概需要如何做、需要注意一些什么方面,来使别人容易地使用你的框架。
抽象和封装,方便使用。首先是对问题有充分的了解,比如构建一个文件解压压缩框架,从使用者的角度出发,只需关注发送给框架一个解压请求,框架完成复杂文件的解压操作,并且在适当的时候通知给是哦难过者,如解压完成、解压出错等。在框架内部去构建对象的关系,通过抽象让其更为健壮、便于更改。其次是API的说明文档。
16、手势控件是什么?手势控件和托控件的区别?
请问什么是手势控件???是不是说手势,或者说是手势插件。什么又是托控件??是拖拽控件吧?把控件拖拽到Storyboard中,是不是这个意思?请描述清楚!!!
17、云端技术:(iCloud)
对用户来说iCloud只是个网络共享目录的URL,它的意图主要是让用户把他们的文档、数据、备份、app文件放到网上去,然后在他们任意的其他设备上,都可以访问该数据。这是它最主要的用途。
要在应用中启用iCloud,首先要为iCloud使用配置App ID。配置好后,生成授权文件(provisioning profile)并在应用中申请权限(entitlement)。
关于iCloud数据存储的理解
(1) 在应用(或者应用套件)中共享数据
在iCloud中,需要通过唯一的ID来识别和申请数据存储容器。通常是应用的App ID,不过也不一定。两个应用可以使用同一个iCloud数据存储容器,从而共享数据。
(2) 在iCloud容器中存储数据
从iOS 5开始,每种设备上的Settings应用都有一个iCloud部分,可以让用户看到iClound中有多少数据用于备份,有多少数据用于应用的同步。当文件存储在iCloud容器中,用户看到的就是一大块数据;而当存储在Documents目录下,用户能看到独立的文件以及大小。Documents目录下的文件可以挨个儿删除,但没有存储在这个目录下的数据看起来就是一大块,只能同时删除。为避免混淆并方便操作,应该把所有用户生成的文件存储在Documents目录下,而把不想让用户看到的繁杂的元数据存储在这个目录之外。
(3) 关于iCloud备份的一些信息
在iOS 5以前,当设备跟iTunes同步时,应用的Documents文件夹下的内容会自动备份。在iOS 5及后续版本的设备上,这些内容会备份到iCloud,但开发者手动保存在iCloud的Documents中的数据不会包括在备份中(因为它们已经在iCloud中了)。要注意这个自动备份和iCloud同步是不同的。备份文档被当做不透明的数据,只能用来完全恢复一个iOS设备。而无论是通过编程还是用户,都无法访问单个文件。
(4) 缺陷
尽管iCloud为用户数据提供了无缝同步和方便的冲突管理,但没有REST API可以用来访问应用存储的数据。而如果开发者要为产品提供一个Web前端的话,REST API是很重要的。任何以服务形式提供跨设备同步的软件都在考虑有没有可能在不久的将来推出基于Web的应用,而iCloud缺失REST API就意味着这基本不可能。尽管苹果自家的应用(Mail、Contacts、Calendar、Reminders和Notes)有很棒的Web前端,但是直到iOS 6都没有提到iCloud的REST API。
缺乏可以用来查看数据的Web接口也使调试变得困难。对于iCloud来说,调试更难,开发者获知数据被备份到iCloud的唯一途径是看到另一台设备成功下载并显示了数据。调试周期长使产品的开发时间成倍增加。
18、UItableView加载图片时怎么处理图片问题?
加载数据策略的问题。你当然不能100张图片一次性的加载到内存当中,这时你就需要采取方法来实现,一般的我们常用的做法是(上面有人也提到了)分步加载(不一次载入全部的数据)也就“懒加载 lazy load”.先载入一部分,在下滑时再加载另一部分。
再者就是可以使用一下“代理”来处理图像的加载,图像未显示前可以显示一个占位图,图片加载完成后,再显示出图片,主要原理还是异步加载,后台处理图片的加载,加载完成后更新主线程上的UI。
可以参见例子:IOS中UITableView异步加载图片的实现 http://blog.csdn.net/enuola/article/details/8639404
19、Ios的新开发语言swift
简单的说:
Swift用来写iOS和OS X程序。
Swift吸取了C和Objective-C的优点,且更加强大易用。
Swift可以使用现有的Cocoa和Cocoa Touch框架。
Swift兼具编译语言的高性能(Performance)和脚本语言的交互性(Interactive)。
详情参见链接:http://mobile.51cto.com/hot-441476.htm
18、新技术swift,GCD,ARC,网络通信,和Github,Google
Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其他的对称多处理系统的系统。这建立在任务并行执行的线程池模式的基础上的。它首次发布在Mac OS X 10.6 ,iOS 4及以上也可用。
系统学习GCD:http://justsee.iteye.com/blog/1883409
ARC是iOS 5推出的新功能,全称叫 ARC(Automatic Reference Counting)。简单地说,就是代码中自动加入了retain/release,原先需要手动添加的用来处理内存管理的引用计数的代码可以自动地由编译器完成了。
该机能在 iOS 5/ Mac OS X 10.7 开始导入,利用 Xcode4.2 可以使用该机能。简单地理解ARC,就是通过指定的语法,让编译器(LLVM 3.0)在编译代码时,自动生成实例的引用计数管理部分代码。有一点,ARC并不是GC,它只是一种代码静态分析(Static Analyzer)工具。参见:http://justcoding.iteye.com/blog/1391548
iOS网络通信类库:ASIHTTPRequest,AFNetworking,MKNetWorkKIt.
ASIHTTPRequest在ios5.0之后就不在维护了,所以之后主要就是AFNetworking和MKNetworkKit。
AFNetWorking:
适合逻辑简单的应用,或者更适合开发资源尚不丰富的团队,因为AFN的易用性,而这样的应用(或团队)对底层网络控件的定制化要求也非常低。
MKNetworkKit:
(1)高度的轻量级,仅仅只有2个主类
(2)自主操作多个网络请求
(3)更加准确的显示网络活动指标
(4)自动设置网络速度,实现自动的2G、3G、wifi切换
(5)自动缓冲技术的完美应用,实现网络操作记忆功能,当你掉线了又上线后,会继续执行未完成的网络请求
(6)可以实现网络请求的暂停功能
(7)准确无误的成功执行一次网络请求,摒弃后台的多次请求浪费
(8)支持图片缓冲
(9)支持ARC机制
(10)在整个app中可以只用一个队列(queue),队列的大小可以自动调整
第三方库 AsyncSocket(GCDAsyncSocket):参见:http://blog.csdn.net/xuqiang918/article/details/16864203
Git是用C语言开发的分布版本控制系统。版本控制系统可以保留一个文件集合的历史记录,并能回滚文件集合到另一个状态(历史记录状态)。另一个状态可以是不同的文件,也可以是不同的文件内容。举个例子,你可以将文件集合转换到两天之前的状态,或者你可以在生产代码和实验性质的代码之间进行切换。文件集合往往被称作是“源代码”。在一个分布版本控制系统中,每个人都有一份完整的源代码(包括源代码所有的历史记录信息),而且可以对这个本地的数据进行操作。分布版本控制系统不需要一个集中式的代码仓库。
当你对本地的源代码进行了修改,你可以标注他们跟下一个版本相关(将他们加到index中),然后提交到仓库中来(commit)。Git保存了所有的版本信息,所以你可以转换你的源代码到任何的历史版本。你可以对本地的仓库进行代码的提交,然后与其他的仓库进行同步。你可以使用Git来进行仓库的克隆(clone)操作,完整的复制一个已有的仓库。仓库的所有者可以通过push操作(推送变更到别处的仓库)或者Pull操作(从别处的仓库拉取变更)来同步变更。
Git支持分支功能(branch)。如果你想开发一个新的产品功能,你可以建立一个分支,对这个分支的进行修改,而不至于会影响到主支上的代码。
Git提供了命令行工具;这个教程会使用命令行。你也可以找到图形工具,譬如与Eclipse配套的EGit工具,但是这些都不会在这个教程中进行描述。
iOS下的github 参见:http://guxiaojje.blog.163.com/blog/static/140942291201272110343064/
19、tadleviewcell内有优化,上下拉双薪及瀑布流内存优化ARC内存处理 delegate
TableView在iOS上的性能优化 http://www.2cto.com/kf/201312/262045.html
UITableView 上拉刷新,下拉刷新http://blog.csdn.net/stackhero/article/details/9035041
IOS 如何实现灵活的瀑布流界面(1)http://blog.csdn.net/cubepeng/article/details/7771882
ios中关于delegate(委托)的使用心得http://blog.csdn.net/huifeidexin_1/article/details/7567731
数据库和多线程的使用
iOS学习之sqlite的创建数据库,表,插入查看数据http://blog.csdn.net/totogo2010/article/details/7702207
IOS多线程编程http://www.cnblogs.com/lyanet/archive/2013/01/11/2856384.html
iOS多线程编程:线程同步总结http://blog.csdn.net/sodaslay/article/details/7744383
毕业生公司面试内容:
1. tableView, 多线程,sqlite,post请求等。
UITableView:
1、UITableView继承自UIScrollView,可以表现为Plain和Grouped两种风格。
2、UITableView有两个Delegate分别为:dataSource和delegate。
dataSource是UITableViewDataSource类型,主要为UITableView提供显示用的数据(UITableViewCell),指定UITableViewCell支持的编辑操作类型(insert,delete和reordering),并根据用户的操作进行相应的数据更新操作,如果数据没有更具操作进行正确的更新,可能会导致显示异常。
delegate是UITableViewDelegate类型,主要提供一些可选的方法,用来控制tableView的选择、指定section的头和尾的显示以及协助完成cell的删除和排序等功能。
多线程:
多线程是为了同步完成多项任务,不是为了提高运行效率,而是为了提高资源使用效率来提高系统的效率。线程是在同一时间需要完成多项任务的时候实现的。
Sqlite和post请求后面有讲解。
2..常见的IOS的知识,比如tableview,数据存储,设计模式等。
数据存储:
NSKeyedArchiver:采用归档的形式来保存数据,该数据对象需要遵守NSCoding协议,并且该对象对应的类必须提供encodeWithCoder:和initWithCoder:方法。前一个方法告诉系统怎么对对象进行编码,而后一个方法则是告诉系统怎么对对象进行解码
NSUserDefaults:用来保存应用程序设置和属性、用户保存的数据。用户再次打开程序或开机后这些数据仍然存在。NSUserDefaults可以存储的数据类型包括:NSData、NSString、NSNumber、NSDate、NSArray、NSDictionary。如果要存储其他类型,则需要转换为前面的类型,才能用NSUserDefaults存储。
使用写入文件的方式保存到磁盘:
第一步:获得文件即将保存的路径:使用NSHomeDirectory函数获得sandbox的路径
第二步:生成在该路径下的文件:NSString *FileName=[documentDirectory stringByAppendingPathComponent:fileName];//fileName就是保存文件的文件名。
第三步:往文件中写入数据:[data writeToFile:FileName atomically:YES];//将NSData类型对象data写入文件,文件名为FileName。
读取文件数据:NSData data=[NSData dataWithContentsOfFile:FileName options:0 error:NULL];//从FileName中读取出数据。
数据库:采用SQLite或core data数据库来存储数据。
设计模式:
Model-View-Controller -----这个设计模式是所以IOS程序的主要架构:模型-视图-控制器(MVC)模式将您的代码分割为几个独立的部分。模型部分定义应用程序的数据引擎,负责维护数据的完整性;视图部分定义应用程序的用户界面,对显示在用户界面上的数据出处则没有清楚的认识;控制器部分则充当模型和控制器的桥梁,帮助实现数据和显示的更新。
Delegation----这个设计模式有助于一个对象的数据传输到另一个对象:委托模式可以对复杂对象进行修改而不需要子类化。与子类化不同的是,您可以照常使用复杂对象,而将对其行为进行修改的定制代码放在另一个对象中,这个对象就称为委托对象。复杂对象需要在预先定义好的时点上调用委托对象的方法,使其有机会运行定制代码。delegation 通过protocol实现。
Target-action----这个设计模式用按钮,等控件把用户的交互变成代码,让程序可以执行:控件通过目标-动作模式将用户的交互通知给您的应用程序。当用户以预先定义好的方式(比如轻点一个按键)进行交互时,控件就会将消息(动作)发送给您指定的对象(目标)。接收到动作消息后,目标对象就会以恰当的方式进行响应(比如在按动按键时更新应用程序的状态)。
Sandboxing---所有的iOS应用程序是放在一个沙盒的,这是为了保护其他应用程序和系统的安全。沙盒的结构影响应用程序文件的放置,数据的备份。还影响其他程序的一些功能。由于安全的原因,iPhone OS将每个应用程序(包括其偏好设置信息和数据)限制在文件系统的特定位置上。这个限制是安全特性的一部分,称为应用程序的“沙箱”。沙箱是一组细粒度的控制,用于限制应用程序对文件、偏好设置、网络资源、和硬件等的访问。在iPhone OS中,应用程序和它的数据驻留在一个安全的地方,其它应用程序都不能进行访问。在应用程序安装之后,系统就通过计算得到一个不透明的标识,然后基于应用程序的根目录和这个标识构建一个指向应用程序家目录的路径。
3,代理是什么,怎么用?
代理的目的是改变或传递控制链。允许一个类在某些特定时刻通知到其他类,而不需要获取到那些类的指针。可以减少框架复杂度。
4,get和post的区别
get是把参数数据队列加到提交表单的ACTION属性所指的URL中,值和表单内各个字段一一对应,在URL中可以看到。
post是通过HTTP post机制,将表单内各个字段与其内容放置在HTML HEADER内一起传送到
ACTION属性所指的URL地址。用户看不到这个过程。、对于get方式,服务器端用Request.QueryString获取变量的值,对于post方式,服务器端用Request.Form获取提交的数据。两种方式的参数都可以用Request来获得。
get传送的数据量较小,不能大于2KB。
post传送的数据量较大,一般被默认为不受限制。但理论上,IIS4中最大量为80KB,IIS5中为100KB。
get安全性非常低,post安全性较高。通过get方法提交数据,可能会带来安全性的问题。比如一个登陆页面。当通过get方法提交数据时,用户名和密码将出现在URL上。如果:
登陆页面可以被浏览器缓存;
其他人可以访问客户的这台机器。
那么,别人即可以从浏览器的历史记录中,读取到此客户的账号和密码。所以,在某些情况下,get方法会带来严重的安全性问题。
post是通过HTTP post机制,将表单内各个字段与其内容放置在HTML HEADER内一起传送到ACTION属性所指的URL地址。用户看不到这个过程。
5, C++中的虚函数和OC中的接口有何区别
OC中的接口(协议)就是用C++中虚函数的原来实现的,其中OC协议中方法分为@required //必须的(相当于C++中的纯虚函数) 和 @optional //可选的(C++中普通虚函数)。
6,谈一下GCD,GCD获得主线程是那个函数。
GCD为Grand Central Dispatch的缩写,GCD是一个替代诸如NSThread等技术的很高效和强大的技术。GCD完全可以处理诸如数据锁定和资源泄漏等复杂的异步编程问题。
dispatch_get_main_queue()。
7,用过多线程吗,项目中那些地方用的。
QQ项目中,接收和发送消息时就用到了多线程,一个线程管理发送,一个线程管理接收。
8,是否使用过CoreAnimation和CoreGraphics。
CoreAnimation:Core Animation是iOS与OS X平台上负责图形渲染与动画的基础设施。Core Animation可以动画视图和其他的可视元素。Core Animation为你完成了实现动画所需的大部分绘帧工作。你只需在配置少量的动画参数(如开始点位置和结束点位置)就可启动Core Animation。Core Animation将大部分实际的绘图任务交给了图形硬件处理,图形硬件会加速图形渲染的速度。这种自动化的图形加速让动画具有更高的帧率且更加平滑,但这并不会增加CPU的负担而导致影响你应用的运行速度。 CoreGraphics: 是一套基于C的API框架,使用了Quartz作为绘图引擎。它提供了低级别、轻量级、高保真度的2D渲染。该框架可以用于基于路径的绘图、变换、颜色管理、脱屏渲染,模板、渐变、遮蔽、图像数据管理、图像的创建、遮罩以及PDF文档的创建、显示和分析
9,UI框架和CA,CG框架的联系是什么?
UI框架内部还是由CA和CG实现的。
10,分别用CA和CG做过些什么动画或者图像上的内容。
11,IOS框架原理。
由于在iOS中当前激活的应用程序只能有一个,所以我们的框架选择的是注入式框架,我们需要将一个测试对象放入到应用程序中,由测试对象来处理测试相关的事件。在iOS应用生命周期里,应用在完成初始启动后,会进入运行循环中,等待处理系统接收到的外部触摸事件,因此最好的嵌入时机是在应用完成初始过程中。在应用初始化过程中,我们加入测试对象创建,并在测试对象初始过程中读取测试脚本,在完成初始后运行测试脚本。测试对象根据测试脚本的描述,搜索需要操作的UI元素,然后对该元素构造指定的操作事件,发送给应用的该元素进行处理,模拟用户的操作行为,从而校验应用的业务功能,框架在应用的初始过程中(applicationDidFinishlaunching)插入了负责执行测试的测试对象,在应用等待事件触发时,模拟了操作事件发送给应用进行处理。
12,NSOperationQueue 和GCD的区别?
NSOpertaionQueue用GCD构建封装的,是GCD的高级抽象
GCD仅仅支持FIFO队列,而NSOperationQueue中的队列可以被重新设置优先级,从而实现不同操作的执行顺序调整。
GCD不支持异步操作之间的依赖关系设置。如果某个操作的依赖另一个操作的数据(生产者-消费者模型是其中之一),使用NSOperationQueue能够按照正确的顺序执行操作。GCD则没有内建的依赖关系支持。
NSOperationQueue支持KVO,意味着我们可以观察任务的执行状态。
了解以上不同,我们可以从以下角度来定义原则
1. 性能,GCD更接近底层,而NSOperationQueue则更高级抽象,所以GCD在追求性能的底层操作来说,是速度最快的。这取决于使用Instruments进行代码性能分析,如有必要的话
2. 从异步操作之间的事务性,顺序行,依赖关系。GCD需要自己写更多的代码来实现,而NSOperationQueue已经内建了这些支持
3. 如果异步操作的过程需要更多的被交互和UI呈现出来,NSOperationQueue会是一个更好的选择。底层代码中,任务之间不太互相依赖,而需要更高的并发能力,GCD则更有优势
13,判断链表里面有环?
算法的思想是设定两个指针p, q,其中p每次向前移动一步,q每次向前移动两步。那么如果单链表存在环,则p和q相遇;否则q将首先遇到null。
这里一个简单的理解是,p和q同时在操场跑步,其中q的速度是p的两倍,当他们两个同时出发时,p跑一圈到达起点,而q此时也刚 好跑完两圈到达起点。
14,objc的消息转发?
当向Objective-C对象发送一个消息,但runtime在当前类及父类中找不到此selector对应的方法时,消息转发(message forwarding)流程开始启动。
动态方法解析(Dynamic Method Resolution或Lazy method resolution)
向当前类(Class)发送resolveInstanceMethod:(对于类方法则为resolveClassMethod:)消息,如果返回YES,则系统认为请求的方法已经加入到了,则会重新发送消息。
快速转发路径(Fast forwarding path)
若果当前target实现了forwardingTargetForSelector:方法,则调用此方法。如果此方法返回除nil和self的其他对象,则向返回对象重新发送消息。
慢速转发路径(Normal forwarding path)
首先runtime发送methodSignatureForSelector:消息查看Selector对应的方法签名,即参数与返回值的类型信息。如果有方法签名返回,runtime则根据方法签名创建描述该消息的NSInvocation,向当前对象发送forwardInvocation:消息,以创建的NSInvocation对象作为参数;若methodSignatureForSelector:无方法签名返回,则向当前对象发送doesNotRecognizeSelector:消息,程序抛出异常退出。
15,如何定位跟踪IOS设备?
现在的移动设备很多都提供定位服务,使用iOS系统的iPhone、iPod Touch和iPad都可以提供位置服务,iOS设备能提供3种不同途径进行定位:Wifi, 蜂窝式移动电话基站, GPS卫星。
主要使用CoreLocation框架,定位时候主要使用CLLocationManager、 CLLocationManagerDelegate和CLLocation。CLLocationManager是定位服务管理类它能够给我们提供获得 设备的位置信息和高度信息,也可以监控设备进入或离开某个区域,它还可以帮助获得设备的运行方向等。CLLocationManagerDelegate 是CLLocationManager类委托协议。CLLocation类是封装了位置和高度信息。
16,ios的控件有多少种实现方式?
拖拽、手写、xib
17,static 关键字的作用
隐藏:当同时编译多个文件时,所有未加static前缀的全局变量和函数都具有全局可见性。
保持变量内容的持久,存储在静态数据区的变量会在程序刚开始运行时就完成初始化,也是唯一的一次初始化。
默认初始为0。
18,线程与进程的区别和联系,
进程(process)是一块包含了某些资源的内存区域。操作系统利用进程把它的工作划分为一些功能单元。进程中所包含的一个或多个执行单元称为线程(thread)。进程还拥有一个私有的虚拟地址空间,该空间仅能被它所包含的线程访问。
进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健 壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。
19,堆和栈的区别
1、栈区(stack)― 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
2、堆区(heap) ― 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。
////多了解一种,即全局区(静态区)数据的存储
3、全局区(静态区)(static)―,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后有系统释放
20,objc的内存管理,如何反转一个链表?,
内存管理原则
(一)原则
只要还有人在使用某个对象,那么这个对象就不会被回收;
只要你想使用这个对象,那么就应该让这个对象的引用计数器+1;
当你不想使用这个对象时,应该让对象的引用计数器-1;
(二)谁创建,谁release
(1)如果你通过alloc,new,copy来创建了一个对象,那么你就必须调用release或者autorelease方法
(2)不是你创建的就不用你去负责
(三)谁retain,谁release
只要你调用了retain,无论这个对象时如何生成的,你都要调用release
(四)总结
有始有终,有加就应该有减。曾经让某个对象计数器加1,就应该让其在最后-1.
反转一个链表:
链表反转
单向链表的反转是一个经常被问到的一个面试题,也是一个非常基础的问题。比如一个链表是这样的: 1->2->3->4->5 通过反转后成为5->4->3->2->1。最容易想到的方法遍历一遍链表,利用一个辅助指针,存储遍历过程中当前指针指向的下一个元素,然后将当前节点元素的指针反转后,利用已经存储的指针往后面继续遍历。源代码如下:
struct linka {
int data;
linka* next;
};
//反转链表
void reverse(linka*& head)
{
if(head ==NULL)
return;
linka*pre, *cur, *ne;
pre=head; /*赋初值*/
cur=head->next;
while(cur)
{
ne = cur->next; /*记住当前节点后一个节点*/
cur->next = pre; /*做反转*/
pre = cur; /*向前走*/
cur = ne;
}
head->next = NULL; /*去尾巴*/
head = pre; /*得到新的头*/
}
21,苹果的推送机制是什么?
苹果提供的推送服务APNs(Apple Push Notification services),具体工作流程和基本原理,参考http://www.2cto.com/kf/201308/233937.html
22.对oc的认识???
1. 兼容性
Objective-C可以说是一种面向对象的C语言,在Objective-C的代码中可以有C和C++语句,它可以调用C的函数,也可以通过C++对象访问方法。
2. 字符串
Objective-C通常不使用C语言风格的字符串。大多数情况下是使用Foundation框架的NSString类型的字符串。NSString类提供了字符串的类包装,支持Unicode,printf风格的格式化工具等等。它是在普通的双引号字符串前放置一个@符号,如下面的例子所示:
NSString* myString = @"My String\n";
NSString* anotherString = [NSString stringWithFormat:@"%d %s", 1, @"String"];
3.类
Objective-C是一种面向对象的语言,定义类是它的基本能力。Objective-C的类声明和实现包括两个部分:接口部分和实现部分。
4.方法
Objective-C是一种面向对象的语言,定义方法也是它的基本能力。Objective-C中方法不是在“.”运算符,而是采用“[]”运算符。有时候方法调用也称为:消息发送。
5. 属性
属性是Objective-C 2.0提出的概念,它是替代对成员变量访问的“读取方法(getter)”和“设定方法(setter)”的手段,为了对类进行封装一般情况下不直接访问成员变量,而是通过属性访问。
6.协议
Objective-C中的协议类似于Java中的接口或C++的纯虚类,只有接口部分定义没有实现部分,即只有h文件没有m文件。
7.分类
Objective-C中的分类是类似与继承机制,通过分类能够扩展父类的功能。
23,简单的UItableview下拉刷新和分页
直接使用第三库EGOTableViewPullRefresh
EGORefreshTableHeaderView.h、EGORefreshTableHeaderView.m
24. get和post的区别 推送会吗?
GET
GET的语义是获取指定URL上的资源
将数据按照variable=value的形式,添加到action所指向的URL后面,并且两者使用“?”连接,各个变量之间使用“&”连接
不安全,因为在传输过程中,数据被放在请求的URL中
传输的数据量小,这主要是因为受URL长度限制
POST
POST的语意是对指定资源“追加/添加”数据
将数据放在数据体中,按照变量和值相对应的方式,传递到action所指向URL
所有数据对用户来说不可见
可以传输大量数据,上传文件只能使用Post
消息推送:NsnotifcationCenter 类来进行消息的注册监听,以及推送消息。进行类之间的通信。
25,背出tableview的代理方法名 多线程操作 copy的使用
tableview代理方法:UITableViewDelegate
多线程操作有三种方式:NSThread,NSOperation,GCD。后两种方式不需要去管理线程之间的关系(线程控制,同步锁等)。GCD是后来的高新技术,能使多核发挥最佳性能
copy:一个可变对象调用copy方法后变成一个不可变的对象,一个不可变的对象调用copy方法后还是一个不可变对象。
26.ARC的优缺点,需要使用的什么调试方式?
优点:可以免去程序员管理内存的麻烦,提高开发效率
缺点:
ARC也有一些缺点,对于初学者来说,可能仅只能将ARC用在objective-c对象上(也即继承自NSObject的对象),但是如果涉及到较为底层的东西,比如Core Foundation中的malloc()或者free()等,ARC就鞭长莫及了,这时候还是需要自己手动进行内存管理。在之后我们会看到一些这方面的例子。另外为了确保ARC能正确的工作,有些语法规则也会因为ARC而变得稍微严格一些。
Xcode中进行断点调试法
27.ios开发流程,内存溢出之类?,
前期的需求,然后开发,测试,发布。
具体开发流程: View层,类之间的通信,网络层,数据处理。
内存溢出:常见错误是数组越界,野指针,内存泄露,都会导致内存溢出错误
28,知道和用过哪些网络协议?
http,tcp/ip
tcp/ip协议:
tcp连接:字节流传输,安全性高 (有三次握手的过程)
手机能够使用联网功能是因为手机底层实现了TCP/IP协议,可以使手机终端通过无线网络建立TCP连接。TCP协议可以对上层网络提供接口,使上层网络数据的传输建立在“无差别”的网络之上。
http:HTTP协议即超文本传送协议(Hypertext Transfer Protocol ),是Web联网的基础,也是手机联网常用的协议之一,HTTP协议是建立在TCP协议之上的一种应用。
29.oc的内存管理
OC的内存管理,归根结底要记住一条黄金法则:谁创建谁释放,谁retain谁释放。
在OC中,当我们对一个对象拥有控制权后,都需要进行释放,但是如何拥有对象的控制权呢?当我们对对象进行了alloc、retain、copy操作后,我们拥有了对象的控制权,因此需要对其进行释放(除了这3个操作,还有个new也能实现alloc类似的功能,但是不建议使用,因此,如果碰见new,也需要进行释放)。
OC采用了引用计数(retain count)的方法。对象的内部保存一个数字,表示被引用的次数,使用alloc或者copy(或者new)方法创建一个对象时,其计数器的值为1,调用retain方法,引用次数就+1,调用release方法就-1,当计数器到0的时候,系统会自动调用alloc方法来释放内存中的对象。当release对象后,其retain count计数如果为0,建议nil一次,例如:
NSObject *obj = [[NSObject alloc] init];
[obj release];
obj = nil;
在这里进行nil赋值的原因是最后一次release对象后,其引用计数可能不立即为0,读者可以打印引用计数看看,可能会为1,而且此时此对象可能会指向其它一段内存区域,如果进行调用,可能会导致其它问题,如可能形成野指针,所以最好是进行一次nil赋值。
对于dealloc方法:
此方法从NSObject继承过来,不需要在.h文件中进行声明;
此方法不需要自己手动调用,当引用计数为0时,系统自动调用;
主要功能是释放成员变量的所有权;
最后调用[super dealloc]释放父类变量。
为防止内存泄漏,并确保最有效地使用内存,应用程序只在需要时才装在数据。至于autorelease,它可以简化内存管理代码,系统会自动释放autorelease池中的对象,但是,如果总是使用autorelease,也可能形成内存泄漏,问题在于autorelease池的释放时机,每当执行应用程序时,系统自动创建autorelease池,系统并不是立即释放autorelease池中的对象,而是在一个run loop之后才释放,一般是微秒级别,本来对象可以立即释放,但是系统很有可能过一些时候才释放autorelease池中的对象,因此我们建议尽量自己进行内存管理,而不要太依赖autorelease。
内存管理的基本原则:
如果使用alloc(或者copy、new)方法创建一个对象,或者使用retain保留一个对象,那么,都要自己释放对象。
在大多数情况下,申请内存的语句数量和释放内存的语句数量应该相等。
尽量少使用内存,用完后记得立即释放。
31.oc怎么实现多态
多态:来自不同类的对象可以定义相同名字的方法
动态类型:这一特性是程序直到执行时才确定对象所属的类
动态绑定:它能使程序直到执行时才确定对象需要调用的实际方法(它与SEL一起实现了objc的多态)
动态绑定和id类型
id类型是一种通用的对象类型,它可以用来存储属于任何类的对象,以这种方式在一个变量中存储不同类型的对象时,在程序的执行期间,这种数据类型真正的优势就体现出来了.
32.oc的多线程同步
使用同步锁 使用NSLock
34.ACPI spec的比如ACPI代表什么意思, CPU 的c state什么意思
ACPI: ACPI表示高级配置和电源管理接口(Advanced Configuration and Power Management Interface)
C state: cpu Processor C-state cpu的运行状态
35, appdelegate几个回调
应用程序运行起来之后会调用:
//应用程序完成启动
应用启动先于视图的加载
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
-(void)applicationDidBecomeActive:(UIApplication *)application
//应用程序进入后台:
-(void)applicationWillResignActive:(UIApplication *)application
-(void)applicationDidEnterBackground:(UIApplication *)application
//应用程序进入前台:
-(void)applicationWillEnterForeground:(UIApplication *)application
-(void)applicationDidBecomeActive:(UIApplication *)application
36,vc几个回调的时机
viewLoad
viewdDidLoad
viewWillAppear
viewDidAppear
viewWillDisappear
viewDidDisappear
37, 写个itoa?
(NSString *)itoa: (int)number
{
NSString *str=[NSString stringWithFormat:@”%i”,number];
return str;
}
38.第三方类库:问得特别多,通信类,分享类 shareKit——分享库
通信类:ASIHttp,SBJson等
分享库:shareSDK,shareKit
参考:http://www.cnblogs.com/chu888chu888/archive/2011/11/18/2254571.html
39.新的知识(ios8新特性,swift语言,2014WWDC大会)
ios8: http://www.25pp.com/news/news_60934.html
swift语言: http://www.csdn.net/article/2014-06-03/2820055
2014WWDC大会: http://it.sohu.com/s2014/wwdc2014/index.shtml?adsid=1
2014WWDC大会视频:英文版 :http://v.youku.com/v_show/id_XNzIwOTA0OTA0.html 中文版: http://www.bilibili.com/video/av1168187/index.html
40.传值和通知(单例模式,代理模式,通知notification)
单例模式:设计一个单例类,即不管用该类实例化多少个对象,其实都是一个,他们内存地址一样。所以可以在同一个工程的不同文件中操作该单例对象。
单例模式: http://www.2cto.com/kf/201311/259408.html
代理模式: http://mobile.51cto.com/hot-404773.htm
通知notification :http://www.2cto.com/kf/201304/207037.html
http://www.2cto.com/kf/201312/263634.html
http://www.2cto.com/kf/201312/265149.html
41.解析类(xml,json 第三方解析类)
常用第三xml解析库GDataXMLNode
常用的ios json库有json-framework、JSONKit、TouchJSON、SBJSon等。
http://blog.csdn.net/lmf208/article/details/7953250
http://www.open-open.com/lib/view/open1338651049594.html
42.真机调试(流程)
http://blog.csdn.net/zhuzhihai1988/article/details/8174902
43.如何在项目中调BUG
一般采用的方法就是断点调试
打印调试
44.在HTTP协议下发送请求
发送get和post请求。
Get请求:将需要请求服务器的内容拼接在http链接地址栏上
Post请求:需要设置http请求方式,请求内容,将请求内容postData提交到服务器上。
45.JS与webview之间的交互
UIWebView是iOS最常用的SDK之一,它有一个stringByEvaluatingJavaScriptFromString方法可以将javascript嵌入页面中,通过这个方法我们可以在iOS中与UIWebView中的网页元素交互。
stringByEvaluatingJavaScriptFromString
使用stringByEvaluatingJavaScriptFromString方法,需要等UIWebView中的页面加载完成之后去调用。我们在界面上拖放一个UIWebView控件。在Load中将google mobile加载到这个控件中,代码如下:
- (void)viewDidLoad
{
[super viewDidLoad];
webview.backgroundColor = [UIColor clearColor];
webview.scalesPageToFit =YES;
webview.delegate =self;
NSURL *url =[[NSURL alloc] initWithString:@"http://www.google.com.hk/m?gl=CN&hl=zh_CN&source=ihp"];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
[webview loadRequest:request];
}
我们在webViewDidFinishLoad方法中就可以通过javascript操作界面元素了。
1、获取当前页面的url。
- (void)webViewDidFinishLoad:(UIWebView *)webView {
NSString *currentURL = [webView stringByEvaluatingJavaScriptFromString:@"document.location.href"];
}
2、获取页面title:
- (void)webViewDidFinishLoad:(UIWebView *)webView {
NSString *currentURL = [webView stringByEvaluatingJavaScriptFromString:@"document.location.href"];
NSString *title = [webview stringByEvaluatingJavaScriptFromString:@"document.title"];
}
3、修改界面元素的值。
NSString *js_result = [webView stringByEvaluatingJavaScriptFromString:@"document.getElementsByName('q')[0].value='朱祁林';"];
4、表单提交:
NSString *js_result2 = [webView stringByEvaluatingJavaScriptFromString:@"document.forms[0].submit(); "];
这样就实现了在google搜索关键字:“朱祁林”的功能。
5、插入js代码
上面的功能我们可以封装到一个js函数中,将这个函数插入到页面上执行,代码如下:
[webView stringByEvaluatingJavaScriptFromString:@"var script = document.createElement('script');"
"script.type = 'text/javascript';"
"script.text = \"function myFunction() { "
"var field = document.getElementsByName('q')[0];"
"field.value='朱祁林';"
"document.forms[0].submit();"
"}\";"
"document.getElementsByTagName('head')[0].appendChild(script);"];
[webView stringByEvaluatingJavaScriptFromString:@"myFunction();"];
看上面的代码:
a、首先通过js创建一个script的标签,type为'text/javascript'。
b、然后在这个标签中插入一段字符串,这段字符串就是一个函数:myFunction,这个函数实现google自动搜索关键字的功能。
c、然后使用stringByEvaluatingJavaScriptFromString执行myFunction函数。
演示:
第一步打开google mobile网站
第二步输入关键字
第三步搜素
总结:这篇文章主要是讲解了stringByEvaluatingJavaScriptFromString的用法,它的功能非常的强大,用起来非常简单,通过它我们可以很方便的操作uiwebview中的页面元素。
46.内存管理(ARC 非ARC)如:在ARC模式下,引入第三方类库,如果第三方类库不兼容ARC机制,怎么办?在ARC机制下如何释放内存?
如果第三方库不是兼容ARC机制的,不许要在工程配置环境设置中设置Build Phases中的compile Source项:
将非ARC的的文件设置成-fno-objc-arc
ARC 特有的两种释放方式:
[self setOjbect:nil];
或者:
self.object=nil;
这里,object 是你要释放的对象名称。
47.下载数据的保存方式,如何实现断续下载(缓存策略)
数据的保存方式:
NSKeyedArchiver:采用归档的形式来保存数据,该数据对象需要遵守NSCoding协议,并且该对象对应的类必须提 供encodeWithCoder:和initWithCoder:方法。前⼀一个方法告诉系统怎么对对象进行编码,而后⼀一个方法则是告诉系统怎 么对对象进行解码。
NSUserDefaults:用来保存应用程序设置和属性、用户保存的数据。用户再次打开程序或开机后这些数据仍然存 在。NSUserDefaults可以存储的数据类型包括:NSData、NSString、NSNumber、NSDate、NSArray、 NSDictionary。如果要存储其他类型,则需要转换为前面的类型,才能用NSUserDefaults存储。
Write写入方式:永久保存在磁盘中。
SQLite:采用SQLite数据库来存储数据。SQLite作为⼀一中小型数据库,应用ios中,跟前三种保存方式相比,相对 比较复杂⼀一些。
参考:http://blog.sina.com.cn/s/blog_7453d50f0101ickz.html
实现断续下载:
iOS开发ASIHTTPRequest断点续传(下载)的内容,其中包括ASIHTTPRequest可以恢复中断的下载,设置一个临时下载路径,断点续传的工作原理等等内容。
从0.94版本开始,ASIHTTPRequest可以恢复中断的下载。
这个特性只对下载数据到文件中有效,你必须为一下情况的request设置allowResumeForFileDownloads 为YES:
任何你希望将来可以断点续传的下载(否则,ASIHTTPRequest会在取消或者释放内存时将临时文件删除)
任何你要进行断点续传的下载
另外,你必须自己设置一个临时下载路径(setTemporaryFileDownloadPath),这个路径是未完成的数据的路径。新的数据将会被添加到这个文件,当下载完成时,这个文件将被移动到downloadDestinationPath 。
- (IBAction)resumeInterruptedDownload:(id)sender
{
NSURL *url = [NSURL URLWithString:
@"http://www.dreamingwish.com/wp-content/uploads/2011/10/asihttprequest-auth.png"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
NSString *downloadPath = @"/Users/ben/Desktop/asi.png";
//当request完成时,整个文件会被移动到这里
[request setDownloadDestinationPath:downloadPath];
//这个文件已经被下载了一部分
[request setTemporaryFileDownloadPath:@"/Users/ben/Desktop/asi.png.download"];
[request setAllowResumeForFileDownloads:YES];
[request startSynchronous];
//整个文件将会在这里
NSString *theContent = [NSString stringWithContentsOfFile:downloadPath];
}
断点续传的工作原理是读取temporaryFileDownloadPath的文件的大小,并使用Range: bytes=x HTTP头来请求剩余的文件内容。
ASIHTTPRequest并不检测是否存在Accept-Ranges头(因为额外的HEAD头请求会消耗额外的资源),所以只有确定服务器支持断点续传下载时,再使用这个特性。
48.socket通信怎么实现?说说你的思路?
1、创建一个socket描述符,socket()函数
2、绑定相应的ip地址及端口号,bind()函数
3、服务器:监听是否有客户端连接 listen()、客户端:连接服务器 connect()函数
4、服务器:接收客户端的请求 accept()函数
5、服务器和客户端相互读写数据 read()、write()函数等
6、关闭连接 close()函数
49.讲一下你对MVC模式的了解?
Modal , View , Controller ,其用意在于将数据与视图分离开来。
MVC 约定, Model 不允许与View 打交道。 Model 是管理数据的, 当Model中的数据发生变化时,与之对应的视图应更新。 这就需要一种机制来支持。为此 iOS 框架提供了两种支持机制: Notification 和KVO (Key-Value Observing)。 KVO 可简单理解为,为你所关注的 Key 对象注册一个监听器。 当有数据发生变化时,就会发出广播给所有的监听器。
MVC 也约定, View 不允许直接引用Modal, 它只能被Controller 所控制。 Controller 控制 View 显示什么数据。我们知道,View 所要显示的数据是来源于 Modal, View 上产生的事件 ( 比如 Touch事件)需要通知 Controller。 既然MVC 不允许直接打交道,就需要提供一种机制。
siOS 确实提供了一种机制, 即 Delegate。 Delegate 这个词, 有人将它译为“委托”,也有人将它译为“代理”。名称上的差异没有什么,重要的是如何理解 Delegate。 Delegate设计模式的引入,就是为了解决UIView与Controller松耦合互动问题。
50.在音乐播放的时候如何实现歌词同步的?
LRC(歌词文件)的每一行的前半部分是一个时间点,然后用timer(定时器)来定时的查询歌词的每一行,每次timer启动时,都去从当前行查询时间,如果当前播放时间大于当前行,就显示下一行歌词,如果小于或等于,就显示当前行歌词。
51.你的上线项目,你主要负责哪些模块的设计?说说?(团队是怎么合作的,说说?)?
敏捷开发scrum:
使用gitHub管理项目。分模块实现相应功能。
网络层的设计:使用post请求,以及xml和json解析的相关知识。
敏捷开发scrum:http://blog.csdn.net/tiwen818/article/details/7526281
52、地图:定位(如何把地图植入到网页,项目中)在一个页面上可以实例化2个地图吗?(百度)
使用UIWebView来显示地图,可以实例化2个地图,但是二者之间的会有相互影响,或者可能其中一个地图完全接收不到相应的事件。
53.Xcode版本信息,你是用XCode哪个版本开发的?
Xcode 5.1
54.你有什么要问公司的吗?(公司的性质,做什么类型的APP应用,发展趋势。。。)
55.多线程(GCD (block))说说block?写一个?
Block:块,或者称之闭包,跟c语言中的函数指针很像。可以简便地编写代码,不需要像调用函数那样麻烦,并提高代码的性能。
参考:http://www.cnblogs.com/pure/archive/2013/03/31/2977420.html
// 后台执行:
dispatch_async(dispatch_get_global_queue(0, 0), ^{
// something
});
// 主线程执行:
dispatch_async(dispatch_get_main_queue(), ^{
// something
});
// 一次性执行:
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// code to be executed once
});
IOS 面试题
内存管理的几条原则是什么?按照默认法则.那些关键字生成的对象
答:需要手动释放?在和property结合的时候怎样有效的避免内存泄露?谁申请,谁释放遵循Cocoa Touch的使用原则;内存管理主要要避免“过早释放”和“内存泄漏”,对于“过早释放”需要注意@property设置特性时,一定要用对特性关键字,对于“内存泄漏”,一定要申请了要负责释放,要细心。关键字alloc 或new 生成的对象需要手动释放;设置正确的property属性,对于retain需要在合适的地方释放,
#import 跟#include 有什么区别,@class 呢,#import<> 跟#import”” 有什么区别?
答:@class一般用于头文件中需要声明该类的某个实例变量的时候用到,在m文件中还是需要使用#import
而#import比起#include的好处就是不会引起重复包含
属性 readwrite,readonly,assign,retain,copy,nonatomic 各是什么作用,在哪种情况下用?
答:assign:指定setter方法用简单的赋值,这是默认操作。你可以对标量类型(如int)使用这个属性。你可以想象一个float,它不是一个对象,所以它不能retain、copy。
retain:指定retain应该在后面的对象上调用,前一个值发送一条release消息。你可以想象一个NSString实例,它是一个对象,而且你可能想要retain它。
copy:指定应该使用对象的副本(深度复制),前一个值发送一条release消息。基本上像retain,但是没有增加引用计数,是分配一块新的内存来放置它。
readonly:将只生成getter方法而不生成setter方法(getter方法没有get前缀)。
readwrite:默认属性,将生成不带额外参数的getter和setter方法(setter方法只有一个参数)。
atomic:对于对象的默认属性,就是setter/getter生成的方法是一个原子操作。如果有多个线程同时调用setter的话,不会出现某一个线程执行setter全部语句之前,另一个线程开始执行setter的情况,相关于方法头尾加了锁一样。
nonatomic:不保证setter/getter的原子性,多线程情况下数据可能会有问题。
看下面程序,第一个NSLog 会输出什么?这时str的retainCount是多少?第二个和第三个呢?为什么?
[cpp] view plaincopyprint?在CODE 上查看代码派生到我的代码片
==================================================
NSMutableArray *ary=[[NSMutableArrayarray]retain];
NSString *str=[NSString stringWithFormat:@"test"];
[str retain];
[ary addObject:str];
NSLog(@"%@,%d",str,[str retainCount]); test, 3
[str retain];
[str release];
[str release];
NSLog(@"%@,%d",str,[str retainCount]); test 2
[ary removeAllObjects];
NSLog(@"%@,%d",str,[str retainCount]);
答:第一个:test, 3 retain会增加一条、addObject增加一条 str初始化也会增加1条
第二个:test, 2 release会减少1条
第三个:test ,1 [ary removeAllObjects];会减少1条
有一张表,里面有三个字段:语文,数学,英语。其中有三条记录分别表示语文70分,数学80分,英语58分,请用一条sql 语句查询出这三条记录并按以下条件显示出来(并写出您的思路):
大于或等于80表示优秀,大于或者等于60表示及格,小于60分表示不及格。
显示格式:
语文 数学 英语
及格 优秀 不及格
select
(case when 语文>=80 then '优秀' else ( case when 语文>=60 then '及格' else '不及格' end) end) as 语文,
(case when 数学>=80 then '优秀' else ( case when 数学>=60 then '及格' else '不及格' end) end) as 数学,
(case when 英语>=80 then '优秀' else ( case when 英语>=60 then '及格' else '不及格' end) end) as 英语
from t_exam
Object-C 基础
Object-C 多继承用什么代替?
答:用协议,协议可以多实现
写一个委托(具体举例),说明委托与通知的区别?
答:Delegate:消息的发送者(sender)告知接收者(receiver)某个事件将要发生,delegate同意然然后发送者响应事件,delegate机制使得接收者可以改变发送者的行为。通常发送者和接收者的关系是直接的一对多的关系。
Notification:消息的发送者告知接收者事件已经发生或者将要发送,仅此而已,接收者并不能反过来影响发送者的行为。通常发送者和接收者的关系是间接的多对多关系。
堆和栈的区别?
答:堆区的特点:空间大,运行速度相对于栈区慢,系统不会自动回收
栈区的特点:空间小,运行速度快,系统会自动回收
IOS有没有垃圾回收?对象是什么时候被release的?Object-C的内存管理机制简单描述?
答:Objective-C 2.0也是有垃圾回收机制的. IOS 有自动引用计数,当对象的引用计数(retainCount)为0时,会被release.
1.当你使用new,alloc和copy方法创建一个对象时,该对象的保留计数器值为1.当你不再使用该对象时,你要负责向该对象发送一条release或autorelease消息.这样,该对象将在使用寿命结束时被销毁.
2.当你通过任何其他方法获得一个对象时,则假设该对象的保留计数器值为1,而且已经被设置为自动释放,你不需要执行任何操作来确保该对象被清理.如果你打算在一段时间内拥有该对象,则需要保留它并确保在操作完成时释放它.
3.如果你保留了某个对象,你需要(最终)释放或自动释放该对象.必须保持retain方法和release方法的使用次数相等.
定义属性时,什么情况使用copy、assign、retain?
答:assign用于简单数据类型,如NSInteger,double,bool,
retain和copy用于对象,
copy用于当a指向一个对象,b也想指向同样的对象的时候,如果用assign,a如果释放,再调用b会crash,如果用copy 的方式,a和b各自有自己的内存,就可以解决这个问题。
retain 会使计数器加一,也可以解决assign的问题。
Self.name = “object”;和name = “object”有什么不同吗?
答:Self.name = “object” 调用的是setName方法
name = “object”是直接给属性赋值,不是调用方法
str1、str2 的值是多少
NSString * responseString = @”www.uzai.com|面试题”;
NSRange range=[responseString rangOfString:@”|”];
Int locateon = range.location;
NSString *str1=[ responseString substringToIndex:location];
NSString *str2=[ responseString substringFromIndex:location+1];
答:str1=@”www.uzai.com”;
str2=@”面试题”;
字符串转换:如何把字符串“10.9.6.8”转换成“10968”?
答: NSString *str=@"10.9.6.8";
NSArray *array=[str componentsSeparatedByString:@"."];//切割
int sum = 0;
for (id obj in array) {//遍历进行相加
int i=[obj intValue];
sum=sum*10+i;
}
NSLog(@"%i",sum);
写一个单例
+(id)sharedInstance
{
//同步锁控制,以防止多线程操作的时候产生两个不同的实例,违背了单例模式
@synchronized (self)
{
if (mySingleTon == nil) {
mySingleTon = [[[super alloc]init]autorelease];
}
}
return mySingleTon;
}
框架平台基础
ViewController 的loadView、viewDidLoad、viewDidUnload、dealloc、viewWillAppear、viewWillDisappear分别是什么时候调用?
答案:
loadView 这是当他们没有正在使用nib视图页面,子类将会创建自己的自定义视图层。绝不能直接调用。
viewDidLoad 在视图加载后被调用,如果是在代码中创建的视图加载器,他将会在loadView方法后被调用,如果是从nib视图页面输出,他将会在视图设置好后后被调用。
viewWillAppear 视图即将可见时调用。默认情况下不执行任何操作
viewDidAppear 视图已完全过渡到屏幕上时调用
viewWillDisappear 视图被驳回时调用,覆盖或以其他方式隐藏。默认情况下不执行任何操作
viewDidDisappear 视图被驳回后调用,覆盖或以其他方式隐藏。默认情况下不执行任何操作
ViewCoutroller 的didReceiveMemoryWarning 是 在什么时候调用的?默认的操作是什么?
答案: 1、当程序收到内存警告时候ViewController会调用didReceiveMemoryWarning这个方法。
2、调用了这个方法之后,对view进行释放并且调用viewDidUnload方法
3、从iOS3.0开始,不需要重载这个函数,把释放内存的代码放到viewDidUnload中去。
CALayer和UIView 的关系?
详细答案有9点,只需摘取前面6点做说明即可:
1. UIView是iOS系统中界面元素的基础,所有的界面元素都是继承自它。它本身完全是由CoreAnimation来实现的。它真正的绘图部分,是由一个CALayer类来管理。UIView本身更像是一个CALayer的管理器,访问它的跟绘图和跟坐标有关的属性,例如frame,bounds等,实际上内部都是在访问它所包含的CALayer的相关属性。
2. UIView有个重要属性layer,可以返回它的主CALayer实例。
// 要访问层,读取UIView实例的layer属性
CALayer *layer = myView.layer
所有从UIView继承来的对象都继承了这个属性。这意味着你可以转换、缩放、旋转,甚至可以在Navigation bars,Tables,Text boxes等其它的View类上增加动画。每个UIView都有一个层,控制着各自的内容最终被显示在屏幕上的方式。
UIView的layerClass方法,可以返回主layer所使用的类,UIView的子类可以通过重载这个方法,来让UIView使用不同的CALayer来显示。代码示例:
- (class)layerClass {
return ([CAEAGLLayer class]);
}
上述代码使得某个UIView的子类使用GL来进行绘制。
3. UIView的CALayer类似UIView的子View树形结构,也可以向它的layer上添加子layer,来完成某些特殊的表示。即CALayer层是可以嵌套的。示例代码:
grayCover = [[CALayer alloc] init];
grayCover.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.2] CGColor];
[self.layer addSubLayer:grayCover];
上述代码会在目标View上敷上一层黑色透明薄膜的效果。
4. UIView的layer树形在系统内部,被维护着三份copy。分别是逻辑树,这里是代码可以操纵的;动画树,是一个中间层,系统就在这一层上更改属性,进行各种渲染操作;显示树,其内容就是当前正被显示在屏幕上得内容。
5. 动画的运作:对UIView的subLayer(非主Layer)属性进行更改,系统将自动进行动画生成,动画持续时间的缺省值似乎是0.5秒。
6. 坐标系统:CALayer的坐标系统比UIView多了一个anchorPoint属性,使用CGPoint结构表示,值域是0~1,是个比例值。这个点是各种图形变换的坐标原点,同时会更改layer的position的位置,它的缺省值是{0.5,0.5},即在layer的中央。
某layer.anchorPoint = CGPointMake(0.f,0.f);
如果这么设置,只会将layer的左上角被挪到原来的中间位置,必须加上这一句:
某layer.position = CGPointMake(0.f,0.f);
最后:layer可以设置圆角显示(cornerRadius),也可以设置阴影 (shadowColor)。但是如果layer树中某个layer设置了圆角,树种所有layer的阴影效果都将不显示了。因此若是要有圆角又要阴影,变通方法只能做两个重叠的UIView,一个的layer显示圆角,一个layer显示阴影......
7.渲染:当更新层,改变不能立即显示在屏幕上。当所有的层都准备好时,可以调用setNeedsDisplay方法来重绘显示。
[gameLayer setNeedsDisplay];
若要重绘部分屏幕区域,请使用setNeedsDisplayInRect:方法,通过在CGRect结构的区域更新:
[gameLayer setNeedsDisplayInRect:CGRectMake(150.0,100.0,50.0,75.0)];
如果是用的Core Graphics框架来执行渲染的话,可以直接渲染Core Graphics的内容。用renderInContext:来做这个事。
[gameLayer renderInContext:UIGraphicsGetCurrentContext()];
8.变换:要在一个层中添加一个3D或仿射变换,可以分别设置层的transform或affineTransform属性。
characterView.layer.transform = CATransform3DMakeScale(-1.0,-1.0,1.0);
CGAffineTransform transform = CGAffineTransformMakeRotation(45.0);
backgroundView.layer.affineTransform = transform;
9.变形:Quartz Core的渲染能力,使二维图像可以被自由操纵,就好像是三维的。图像可以在一个三维坐标系中以任意角度被旋转,缩放和倾斜。CATransform3D的一套方法提供了一些魔术般的变换效果。
如何更改nav 的背景图片
如果导航条要增加背景图片,但是这个背景图片的宽和高保持和导航条默认的一样。这样可以考虑用下面的代码实现:
UIImageView *barSeperator = [[UIImageView alloc] initWithImage:[cache retrieveObjectNamed:@"[email protected]"]];
barSeperator.frame = CGRectMake(0, self.navigationController.navigationBar.bounds.size.height - 2, 320, 2);
UIImageView *barImage = [[UIImageView alloc] initWithImage:[cache retrieveObjectNamed:@"[email protected]"]];
barImage.frame = CGRectMake(0, 0, 320, self.navigationController.navigationBar.bounds.size.height - 2);
[self.navigationController.navigationBar addSubview:barImage];
[self.navigationController.navigationBar addSubview:barSeperator];
原理很简单就是在导航条上面加一个背景图片,不过这个方法最好写在- (void)viewWillAppear中,而在viewWillDisappear的时候把这个背景条去掉,这样就不会影响下一个导航条的外观。那么在增加了这个背景条的同时,最好再用自己设计的UIBarButtonItem,因为现再用系统自带的就显的及其不自然。这样就需要你在自己设计的viewcontroller中navigationItem的hidden属性设为YES,然后自己向导航条上增加UIButton就行了,也就是完全不用UIBarButtonItem了,因为这个控件的形状你很难改变。
interface 和protocol的理解,举一个使用例子
头文件interface的作用是,定义对外的接口。
然而,它的作用也只有这个而已。头文件无法保证对外接口一定会被实现。
根据.h文件是否定义方法、.m文件是否实现方法,可以分为三类:
第一类是.h文件定义方法,.m文件也实现了方法,这是最common的做法,也是最没有问题的做法。
第二类是.h文件定义方法,但.m文件没有实现该方法。此时.m文件的@implementaion代码会提示“imcomplete implementation”,意思是头文件定义的方法和变量,没有被完全实现。
比如:.h文件里这样定义:
@interface Test : NSObject{}
-(void)hello;
@end
但是在.m文件里没有实现这个方法。在外部,我们可以调用这个方法,它在编译时没问题,但在运行时会出现“unrecognized selector sent to instance”错误。
第三类是.h文件没有定义,但.m文件里有这个方法。
比如,在.m文件里这样实现:
#import "Test.h"
@implementation Test
-(void)hello{
NSLog(@"hello world!");
}
@end
这时,hello()这个函数相当于私有函数,我们只可以在类中用[self hello]调用,而不能在外部调用。
objective-c中的头文件,只是为了编译时更方便而已,它并不是真正的interface。
相对而言,protocol才算是真正意义上的interface,它的意义和Java中的接口差不多。
protocol的方法分两种类型,一类是必须实现的,一类是不一定实现的。不一定实现的方法其实和.h文件里定义的差不多。而一定要实现的方法就是比较有用的了。
我们可以使用这样的方法来初始化一个实现了名为Hello的protocol的类:
id
protocol除了作为接口的作用之外,经常还用来作为类之间进行交互的方法,这时它叫作delegate。delegate的主要作用,是把一个类需要做的一部分事情,让另一个类来完成。
A、B 两个应用程序,如何互相打开。(比如在自己的app中打开appstore)
答案:NSURL* url = [NSURL URLWithString: @“myapp://XXX"];
[[UIApplication sharedApplication] openURL: url];
其中的"lifengzhong"便是我为此应用注册的自定义协议名称,其他应用如果想调用我的应用,只要打开形似:“myapp://XXX”的URL便可以了
这里的XXX是自定义的参数,你可以根据自己需要定义URL的格式
UITableView 和UIScrollView 的关系、区别
答案:相同点:UITableView实现了UIScrollView协议,且继承于UIScrollView,两个组件都可以滑动。
相异点:UITableView是逐步加载UITableViewCell,以后每次滚动时,重绘cell;UIScrollView是初始化所有其子视图,以后每次滚动,不再重绘其子视图,所以UITableView滑动起来比较卡,而UIScrollView滑动比较顺畅;在数据量比较多的情况下,应该使用UITableView,因为cell可以复用,使用内存相对较少,而UIScrollView使用内存较多;另外UITableView可以刷新数据,reloaddata等,而scrollview的数据是固定的,除非重新初始化
如何在UILabel上加上一个删除线
答案:下面是UILabelStrikeThrough.h文件
/*
* 用于在UILabel上画删除线
*/
#import
@interface UILabelStrikeThrough :UILabel
{
BOOL isWithStrikeThrough;
}
@property (nonatomic,assign) BOOL isWithStrikeThrough;
@end
===========================================================================
下面是UILabelStrikeThrough.m文件
#import"UILabelStrikeThrough.h"
@implementation UILabelStrikeThrough
@synthesize isWithStrikeThrough;
- (void)drawRect:(CGRect)rect
{
if (isWithStrikeThrough)
{
CGContextRef c = UIGraphicsGetCurrentContext();
CGFloat red[4] = {1.0f,0.0f, 0.0f,0.8f}; //红色
//CGFloat black[4] = {0.0f, 0.0f, 0.0f, 0.5f};//黑色
CGContextSetStrokeColor(c, red);
CGContextSetLineWidth(c, 2);
CGContextBeginPath(c);
//画直线
//CGFloat halfWayUp = rect.size.height/2 + rect.origin.y;
//CGContextMoveToPoint(c, rect.origin.x, halfWayUp );//开始点
//CGContextAddLineToPoint(c, rect.origin.x + rect.size.width, halfWayUp);//结束点
//画斜线
CGContextMoveToPoint(c, rect.origin.x, rect.origin.y+5 );
CGContextAddLineToPoint(c, (rect.origin.x + rect.size.width)*0.5, rect.origin.y+rect.size.height-5); //斜线
CGContextStrokePath(c);
}
[superdrawRect:rect];
}
- (void)dealloc
{
[super dealloc];
}
@end
===========================================================================
调用代码:
UILabelStrikeThrough *originalPrice=[[[UILabelStrikeThroughalloc] initWithFrame:CGRectMake(coinPic.frame.origin.x+coinPic.frame.size.width+5,0, 120,15)]autorelease];
originalPrice.isWithStrikeThrough=TRUE;
UIWebView 一共有几种加载数据的方式?
答案:API提供了三种方法:
- (void)loadRequest:(NSURLRequest *)request;
- (void)loadHTMLString:(NSString *)string baseURL:(NSURL *)baseURL;
- (void)loadData:(NSData *)data MIMEType:(NSString *)
MIMEType textEncodingName:(NSString *)textEncodingName baseURL:(NSURL *)baseURL;
1、直接给出url地址即可将web content载入。
NSString *path = @"http://theo2life.com";
NSURL *url = [[NSURL alloc] initWithString:path];
[self.webView loadRequest:[NSURLRequest requestWithURL:url]];
2、将本地html文件内容嵌入webView
NSString *resourcePath = [ [NSBundle mainBundle] resourcePath];
NSString *filePath = [resourcePath stringByAppendingPathComponent:@"test.html"];
NSString *htmlstring =[[NSString alloc] initWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
[self.webView loadHTMLString:htmlstring baseURL:[NSURL fileURLWithPath: [[NSBundle mainBundle] bundlePath]]];
如果不从html文件载入你也可以这样:
NSString *HTMLData = @"ddd";
[self.webView loadHTMLString:HTMLData baseURL:[NSURL fileURLWithPath: [[NSBundle mainBundle] bundlePath]]];
baseURL:[NSURL fileURLWithPath: [[NSBundle mainBundle] bundlePath]]
这段指出HTMLData所引用的其他文件资源的基本路径,如果baseURL:nil图片信息将不会显示出来~
3、同2,更详细的给出了web content的编码方式。
DidFinishLaunchingWithOptions什么时候运行,会带有什么数据,举例三种以上数据
答案:iOS 程序启动时总会调用application:didFinishLaunchingWithOptions:,其中第二个参数launchOptions为NSDictionary类型的对象,里面存储有此程序启动的原因。launchOptions中的可能键值见UIApplication Class Reference的Launch Options Keys节 。
若用户直接启动,lauchOptions内无数据;
若由其他应用程序通过openURL:启动,则UIApplicationLaunchOptionsURLKey对应的对象为启动URL(NSURL),UIApplicationLaunchOptionsSourceApplicationKey对应启动的源应用程序的bundle ID (NSString);
若由本地通知启动,则UIApplicationLaunchOptionsLocalNotificationKey对应的是为启动应用程序的的本地通知对象(UILocalNotification);
若由远程通知启动,则UIApplicationLaunchOptionsRemoteNotificationKey对应的是启动应用程序的的远程通知信息userInfo(NSDictionary);
其他key还有UIApplicationLaunchOptionsAnnotationKey,UIApplicationLaunchOptionsLocationKey,
UIApplicationLaunchOptionsNewsstandDownloadsKey。
如果要在启动时,做出一些区分,那就需要在下面的代码做处理。
比如:您的应用可以被某个其它应用调起(作为该应用的子应用),要实现单点登录,那就需要在启动代码的地方做出合理的验证,并跳过登录。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSURL *url = [options objectForKey:UIApplicationLaunchOptionsURLKey];
if(url) { }
NSString *bundleId = [options objectForKey:UIApplicationLaunchOptionsSourceApplicationKey];
if(bundleId) { }
UILocalNotification * localNotify = [options objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if(localNotify) { }
NSDictionary * userInfo = [options objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if(userInfo) { }
}
如何用多语言发布程序
多语言在应用程序中一般有两种做法:
一、程序中提供给用户自己选择的机会;
二、根据当前用户当前移动设备的语言自动将我们的app切换对应语言。
第一种做法比较简单完全靠自己的发挥了,这里主要讲第二种做法,主要分一下几点:
1.本地化应用程序名称
2.本地化字符串
3.本地化图片
4.本地化其他文件
具体步骤:http://blog.csdn.net/wangqiuyun/article/details/7875442
C、 C++面试题
1、struct 和 class 的区别
答案:struct 的成员默认是公有的,而类的成员默认是私有的。struct 和 class 在其他方面是功能相当的。
2、分别写出BOOL,int,float,指针类型的变量a 与“零”的比较语句。
答案:
BOOL : if ( !a ) or if(a)int : if ( a ==0)float : const EXPRESSION EXP =0.000001
if ( a < EXP&& a >-EXP)
3、什么是“引用”?申明和使用“引用”要注意哪些问题?
答:引用就是某个目标变量的“别名”(alias),对应用的操作与对变量直接操作效果完全相同。申明一个引用的时候,切记要对其进行初始化。引用声明完毕后,相当于目标变量名有两个名称,即该目标原名称和引用名,不能再把该引用名作为其他变量名的别名。声明一个引用,不是新定义了一个变量,它只表示该引用名是目标变量名的一个别名,它本身不是一种数据类型,因此引用本身不占存储单元,系统也不给引用分配存储单元。不能建立数组的引用。
4、将“引用”作为函数参数有哪些特点?
(1)传递引用给函数与传递指针的效果是一样的。这时,被调函数的形参就成为原来主调函数中的实参变量或对象的一个别名来使用,所以在被调函数中对形参变量的操作就是对其相应的目标对象(在主调函数中)的操作。
(2)使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作;而使用一般变量传递函数的参数,当发生函数调用时,需要给形参分配存储单元,形参变量是实参变量的副本;如果传递的是对象,还将调用拷贝构造函数。因此,当参数传递的数据较大时,用引用比用一般变量传递参数的效率和所占空间都好。
(3)使用指针作为函数的参数虽然也能达到与使用引用的效果,但是,在被调函数中同样要给形参分配存储单元,且需要重复使用"*指针变量名"的形式进行运算,这很容易产生错误且程序的阅读性较差;另一方面,在主调函数的调用点处,必须用变量的地址作为实参。而引用更容易使用,更清晰。
5、“引用”与指针的区别是什么?
指针通过某个指针变量指向一个对象后,对它所指向的变量间接操作。程序中使用指针,程序的可读性差;
而引用本身就是目标变量的别名,对引用的操作就是对目标变量的操作。此外,就是上面提到的对函数传ref和pointer的区别。
6、结构与联合有和区别?
1. 结构和联合都是由多个不同的数据类型成员组成, 但在任何同一时刻, 联合中只存放了一个被选中的成员(所有成员共用一块地址空间), 而结构的所有成员都存在(不同成员的存放地址不同)。
2. 对于联合的不同成员赋值, 将会对其它成员重写, 原来成员的值就不存在了, 而对于结构的不同成员赋值是互不影响的。
7、已知strcpy的函数原型:char *strcpy(char *strDest, const char *strSrc)其中strDest 是目的字符串,strSrc 是源字符串。不调用C++/C 的字符串库函数,请编写函数 strcpy。
char * strcpy( char *strDest, const char *strSrc )
{
assert( (strDest != NULL) &&(strSrc != NULL) );
char *address = strDest;
while( (*strDest++ = * strSrc++) != ‘\0’ );
return address;
}
8、已知String类定义如下:
class String
{
public:
String(const char *str = NULL); // 通用构造函数
String(const String &another); // 拷贝构造函数
~String(); // 析构函数
String& operater =(const String &rhs); // 赋值函数
private:
char* m_data; // 用于保存字符串
};
尝试写出类的成员函数实现。
9、 .h头文件中的ifndef/define/endif 的作用?
答:防止该头文件被重复引用。
10、#include
答:前者是从Standard Library的路径寻找和引用file.h,而后者是从当前工作路径搜寻并引用file.h。
11、面向对象的三个基本特征,并简单叙述之?
1. 封装:将客观事物抽象成类,每个类对自身的数据和方法实行protection(private, protected,public)
2. 继承:广义的继承有三种实现形式:实现继承(指使用基类的属性和方法而无需额外编码的能力)、可视继承(子窗体使用父窗体的外观和实现代码)、接口继承(仅使用属性和方法,实现滞后到子类实现)。前两种(类继承)和后一种(对象组合=>接口继承以及纯虚函数)构成了功能复用的两种方式。
3. 多态:系统能够在运行时,能够根据其类型确定调用哪个重载的成员函数的能力,称为多态性。
12、重载(overload)和重写(overried,有的书也叫做“覆盖”)的区别?
从定义上来说:
重载:是指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)。
重写:是指子类重新定义父类虚函数的方法。
从实现原理上来说:
重载:编译器根据函数不同的参数表,对同名函数的名称做修饰,然后这些同名函数就成了不同的函数(至少对于编译器来说是这样的)。如,有两个同名函数:function func(p:integer):integer;和function func(p:string):integer;。那么编译器做过修饰后的函数名称可能是这样的:int_func、str_func。对于这两个函数的调用,在编译器间就已经确定了,是静态的。也就是说,它们的地址在编译期就绑定了(早绑定),因此,重载和多态无关!
重写:和多态真正相关。当子类重新定义了父类的虚函数后,父类指针根据赋给它的不同的子类指针,动态的调用属于子类的该函数,这样的函数调用在编译期间是无法确定的(调用的子类的虚函数的地址无法给出)。因此,这样的函数地址是在运行期绑定的(晚绑定)。
13、请说出const与#define 相比,有何优点?1) const 常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误。
有些集成化的调试工具可以对const 常量进行调试,但是不能对宏常量进行调试。
14、写一个函数找出一个整数数组中,第二大的数
答案:
const int MINNUMBER = -32767;
int find_sec_max( int data[] , int count)
{
int maxnumber = data[0];
int sec_max = MINNUMBER;
for ( int i = 1; i < count; i++)
{
if ( data[i] > maxnumber )
{
sec_max = maxnumber;
maxnumber = data[i];
}
else
{
if ( data[i] > sec_max ) sec_max = data[i];
}
}
return sec_max;
}
15、以下为WindowsNT下的32位C++程序,请计算sizeof的值
void Func ( char str[100] )
{
sizeof( str ) =?
}void*p = malloc( 100 );
sizeof ( p ) =?
解答:
sizeof( str ) = 4
sizeof ( p ) = 4
16、static有什么用途,C语言中?
1)在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。
2) 在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量。
3) 在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用
17、Const的作用?
1、可以保护被修饰的东西,防止意外的修改,增强程序的健壮性。
2、修饰谁,谁就不可变。
18、局部变量能否和全局变量重名?
答:能,局部会屏蔽全局。要用全局变量,需要使用"::"
29、用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题)
#define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL
20、常要用到无限循环,你怎么样用C编写无限循环呢?
这个问题用几个解决方案。我首选的方案是:
while(1) { }
一些程序员更喜欢如下方案:
for(;;) { }
21、一个学生的信息是:姓名,学号,性别,年龄等信息,用一个链表,把这些学生信息连在一起, 给出一个age, 在些链表中删除学生年龄等于age的学生信息。
struct stu{
char name[20];
char sex;
int no;
int age;
struct stu * next;
}*linklist;
struct stu*creatlist(int n)
{
int i;
//h为头结点,p为前一结点,s为当前结点
struct stu*h,*p,*s;
h = (struct stu*)malloc(sizeof(struct stu));
h->next = NULL;
p=h;
for(i=0;i
{
s = (struct stu*)malloc(sizeof(struct stu));
p->next = s;
printf("Pleaseinput the information of the student: name sex no age \n");
scanf("%s %c%d %d",s->name,&s->sex,&s->no,&s->age);
s->next = NULL;
p = s;
}
printf("Createsuccessful!");
return(h);
}
Void deletelist(struct stu *s,int a)
{
struct stu *p;
while(s->age!=a)
{
p = s;
s = s->next;
}
if(s==NULL)
printf("Therecord is not exist.");
else
{
p->next =s->next;
printf("Deletesuccessful!");
}
}
void display(structstu *s)
{
s = s->next;
while(s!=NULL)
{
printf("%s %c%d %d\n",s->name,s->sex,s->no,s->age);
s = s->next;
}
}
int main()
{
struct stu *s;
int n,age;
printf("Pleaseinput the length of seqlist:\n");
scanf("%d",&n);
s = creatlist(n);
display(s);
printf("Pleaseinput the age:\n");
scanf("%d",&age);
deletelist(s,age);
display(s);
return 0;
}
22、实现一个函数,把一个字符串中的字符从小写转为大写。
/*
函数名称:big_lower
函数功能:将一个字符串数组中的小写字母改为大写
函数参数:ops
*/
void big_lower(char *ops)
{
int i = 0;
while(ops[i] != '\0')
{
if (ops[i] >= 'a' && ops[i] <= 'z')
{
ops[i] -= 32;
}
i++;
}
}
23、C++中为什么用模板类。
答:(1)可用来创建动态增长和减小的数据结构
(2)它是类型无关的,因此具有很高的可复用性。
(3)它在编译时而不是运行时检查数据类型,保证了类型安全
(4)它是平台无关的,可移植性
(5)可用于基本数据类型
24、new delete 与malloc free 的联系与区别?
答案:都是在堆(heap)上进行动态的内存操作。用malloc函数需要指定内存分配的字节数并且不能初始化对象,new 会自动调用对象的构造函数。delete 会调用对象的destructor,而free 不会调用对象的destructor.
25、当一个类A 中没有任何成员变量与成员函数,这时sizeof(A)的值是多少?
答案:1。(Autodesk)肯定不是零。举个反例,如果是零的话,声明一个class A[10]对象数组,而每一个对象占用的空间是零,这时就没办法区分A[0],A[1]…了。
26、子类析构时要调用父类的析构函数吗?
析构函数调用的次序是先派生类的析构后基类的析构,也就是说在基类的的析构调用的时候,派生类的信息已经全部销毁了定义一个对象时先调用基类的构造函数、然后调用派生类的构造函数;析构的时候恰好相反:先调用派生类的析构函数、然后调用基类的析构函数。
27、多态,虚函数,纯虚函数
多态:是对于不同对象接收相同消息时产生不同的动作。C++的多态性具体体现在运行和编译两个方面:在程序运行时的多态性通过继承和虚函数来体现;
在程序编译时多态性体现在函数和运算符的重载上
虚函数:在基类中冠以关键字 virtual 的成员函数。 它提供了一种接口界面。允许在派生类中对基类的虚函数重新定义。
纯虚函数的作用:在基类中为其派生类保留一个函数的名字,以便派生类根据需要对它进行定义。作为接口而存在 纯虚函数不具备函数的功能,一般不能直接被调用。
从基类继承来的纯虚函数,在派生类中仍是虚函数。如果一个类中至少有一个纯虚函数,那么这个类被称为抽象类(abstract class)。
抽象类中不仅包括纯虚函数,也可包括虚函数。l抽象类必须用作派生其他类的基类,而不能用于直接创建对象实例。但仍可使用指向抽象类的指针支持运行时多态性。
28、结构与联合有和区别?
. 结构和联合都是由多个不同的数据类型成员组成, 但在任何同一时刻, 联合中只存放了一个被选中的成员(所有成员共用一块地址空间), 而结构的所有成员都存在(不同成员的存放地址不同)。
(2). 对于联合的不同成员赋值, 将会对其它成员重写, 原来成员的值就不存在了, 而对于结构的不同成员赋值是互不影响的。
C/C++测试题
前几个部分从编程风格、函数设计、内存管理和类的一些相关知识和注意点出发,对C/C++基础知识和笔试面试易考察的点进行了归纳总结。下面这是针对前述知识出的一份测试题,也是一些易考点,大家认真阅读了之前的部分,这些题大家都很容易就能做出来。
一、请填写BOOL, float, 指针变量 与“零值”比较的 if 语句。
提示:这里“零值”可以是0 , 0.0 , FA LSE 或者“空指针”。例如 int 变量 n 与“零值”
比较的 if 语句为:
if ( n == 0 )
if ( n != 0 )
以此类推。
请写出 BOOL flag 与“零值”比较的 if 语句:
请写出 float x 与“零值”比较的 if 语句:
请写出 char *p 与“零值”比较的 if 语句:
二、以下为Windows xp 下的32位C++ 程序,请计算sizeof 的值
char str[] = “Hello” ;
char *p = str ;
int n = 10;
请计算
sizeof (str ) =
sizeof (p) =
sizeof (n) =
void Func ( char str[100])
{
}
请计算
sizeof( str ) =
void *p = malloc( 100 );
请计算
sizeof ( p ) =
三、简答
1 、头文件中的 ifndef/define/endif 干什么用?
2 、#include
3 、const有什么用途?(请至少说明两种)
4 、在C++ 程序中调用被 C编译器编译后的函数,为什么要加 extern“C” 声明?
5 、请简述以下两个for 循环的优点和缺点
// 第一个
for (i=0; i
{
if (condition)
DoSomething();
else
DoOtherthing();
}
// 第二个
if (condition)
{
for (i=0; i
DoSomething();
}
else
{
for (i=0; i
DoOtherthing();
}
四、看程序写结果题
请问运行以下Test函数会有什么样的结果?
//第一个
void GetMemory(char *p)
{
p = (char *)malloc(100);
}
void Test(void)
{
char *str = NULL;
GetMemory(str);
strcpy(str, "hello world");
printf(str);
}
//第二个
char *GetMemory(void)
{
char p[] = "hello world";
return p;
}
void Test(void)
{
char *str = NULL;
str = GetMemory();
printf(str);
}
//第三个
Void GetMemory2(char **p, int num)
{
*p = (char *)malloc(num);
}
void Test(void)
{
char *str = NULL;
GetMemory(&str, 100);
strcpy(str, "hello");
printf(str);
}
//第四个
void Test(void)
{
char *str = (char *) malloc(100);
strcpy(str, “ hello ” );
free(str);
if(str != NULL)
{
strcpy(str, “ world ” );
printf(str);
}
}
五、C函数编写题
已知strcpy 函数的原型是
char *strcpy(char *strDest, const char *strSrc);
其中strDest是目的字符串,strSrc 是源字符串。
(1 )不调用C++/C 的字符串库函数,请编写函数 strcpy
(2 )strcpy 能把strSrc 的内容复制到strDest,为什么还要char * 类型的返回值?
六、类函数编写题
已知类String的原型为:
class String
{
public:
String(const char *str = NULL); // 普通构造函数
String(const String &other); // 拷贝构造函数
~ String(void); // 析构函数
String & operate =(const String &other); // 赋值函数
private:
char *m_data; // 用于保存字符串
};
请编写String的上述4 个函数。
一、请填写BOOL , float, 指针变量 与“零值”比较的 if 语句。
提示:这里“零值”可以是0 , 0.0 , FALSE 或者“空指针”。例如 int 变量 n 与“零值”
比较的 if 语句为:
if ( n == 0 )
if ( n != 0 )
以此类推。
请写出 BOOL flag 与“零值”比较的 if 语句:
if ( flag )
if ( !flag )
请写出 float x 与“零值”比较的 if 语句:
const float EPSINON = 0.00001;
if ((x >= - EPSINON) && (x <= EPSINON)
不可将浮点变量用“==”或“!= ”与数字比较,应该设法转化成“>=”或“ <=”此类形式
请写出 char *p 与“零值”比较的 if 语句:
if (p == NULL)
if (p != NULL)
二、以下为Windows XP 下的32位C++ 程序,请计算size of 的值
[cpp] view plaincopy
char str[] = “Hello” ;
char *p = str ;
int n = 10;
请计算
sizeof (str ) = 6
sizeof (p) = 4
sizeof (n) = 4
void Func ( char str[100])
{
}
请计算
sizeof( str ) = 4
void *p = malloc( 100 );
请计算
sizeof ( p ) = 4
三、简答
1 、头文件中的 ifndef/define/endif 干什么用?
答:防止该头文件被重复引用。
2 、#include
答:对于#include
对于#include “filename.h” ,编译器从用户的工作路径开始搜索 filename.h
3 、const有什么用途?(请至少说明两种)
答:(1 )可以定义 const 常量
(2 )const 可以修饰函数的参数、返回值,甚至函数的定义体。被const 修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。
4 、在C++ 程序中调用被 C编译器编译后的函数,为什么要加 extern“C” 声明?
答:C++ 语言支持函数重载,C 语言不支持函数重载。函数被C++ 编译后在库中的名字与C 语言的不同。假设某个函数的原型为: void foo(int x, int y);
该函数被 C 编译器编译后在库中的名字为_foo,而C++ 编译器则会产生像_foo_int_int 之类的名字。
C++ 提供了C 连接交换指定符号extern “C ”来解决名字匹配问题。
5 、请简述以下两个for 循环的优点和缺点
// 第一个
for (i=0; i
{
if (condition)
DoSomething();
else
DoOtherthing();
}
优点:程序简洁
缺点:多执行了N-1 次逻辑判断,并且打断了循环“流水线”作业,使得编译器不能对循环进行优化处理,降低了效率。
// 第二个
if (condition)
{
for (i=0; i
DoSomething();
}
else
{
for (i=0; i
DoOtherthing();
}
优点:循环的效率高
缺点:程序不简洁
四、看程序写结果题
请问运行以下Test函数会有什么样的结果?
//第一个
void GetMemory(char *p)
{
p = (char *)malloc(100);
}
void Test(void)
{
char *str = NULL;
GetMemory(str);
strcpy(str, "hello world");
printf(str);
}
答:程序崩溃。
因为GetMemory并不能传递动态内存,Test函数中的 str一直都是 NULL 。 strcpy(str, "hello wo rld");将使程序崩溃。
//第二个
char *GetMemory(void)
{
char p[] = "hello world";
return p;
}
void Test(void)
{
char *str = NULL;
str = GetMemory();
printf(str);
}
答:可能是乱码。
因为GetMemory 返回的是指向“栈内存”的指针,该指针的地址不是 NULL ,但其原现的内容已经被清除,新内容不可知。
//第三个
Void GetMemory2(char **p, int num)
{
*p = (char *)malloc(num);
}
void Test(void)
{
char *str = NULL;
GetMemory(&str, 100);
strcpy(str, "hello");
printf(str);
}
答:
(1 )能够输出hello
(2 )内存泄漏
//第四个
void Test(void)
{
char *str = (char *) malloc(100);
strcpy(str, “ hello ” );
free(str);
if(str != NULL)
{
strcpy(str, “ world ” );
printf(str);
}
}
答:篡改动态内存区的内容,后果难以预料,非常危险。
因为free(str);之后,str 成为野指针, if(str != NULL)语句不起作用。
五、C函数编写题
已知strcpy 函数的原型是
char *strcpy(char *strDest, const char *strSrc);
其中strDest是目的字符串,strSrc 是源字符串。
(1 )不调用C++/C 的字符串库函数,请编写函数 strcpy
[cpp] view plaincopy
char *strcpy(char *strDest, const char *strSrc);
assert((strDest!=NULL) && ( strSrc !=NULL));
char *address = strDest; // 2 分
while( (* strDest++ = * strSr c ++) != ‘\ 0’)
NULL ;
return address ;
(2 )strcpy 能把strSrc 的内容复制到strDest,为什么还要char * 类型的返回值?
答:为了实现链式表达式。
例如 int length = strlen( strcpy( strDest, “hello world”) );
六、类函数编写题:已知类String的原型为:
class String
{
public:
String(const char *str = NULL); // 普通构造函数
String(const String &other); // 拷贝构造函数
~ String(void); // 析构函数
String & operate =(const String &other); // 赋值函数
private:
char *m_data; // 用于保存字符串
};
请编写String的上述4 个函数。
[cpp] view plaincopy
// String 的析构函数
String : : ~String(void)
{
delete [] m_data;
// 由于m_data是内部数据类型,也可以写成 delete m_data;
}
// String 的普通构造函数
String : : String(const char *str) // 6 分
{
if(str==NULL)
{
m_data = new char[1]; // 若能加 NULL 判断则更好
*m_data = ‘ \ 0 ’ ;
}
else
{
int length = strlen(str);
m_data = new char[length+1]; // 若能加 NULL 判断则更好
strcpy(m_data, str);
}
}
// 拷贝构造函数
String::String(const String &other) // 3 分
{
int length = strlen(other.m_data);
m_data = new char[length+1]; // 若能加 NULL 判断则更好
strcpy(m_data, other.m_data);
}
// 赋值函数
String & String::operate =(const String &other) // 13分
{
// (1) 检查自赋值 // 4 分
if(this == &other)
return *this;
// (2) 释放原有的内存资源 // 3 分
delete [] m_data;
// (3 )分配新的内存资源,并复制内容 // 3 分
int length = strlen(other.m_data);
m_data = new char[length+1]; // 若能加 NULL 判断则更好
strcpy(m_data, other.m_data);
// (4 )返回本对象的引用 // 3 分
return *this;
}
常问的CC++基础题
这一部分是C/C++程序员在面试的时候会被问到的一些题目的汇总。来源于基本笔试面试书籍,可能有一部分题比较老,但是这也算是基础中的基础,就归纳归纳放上来了。大牛们看到一笑而过就好,普通人看看要是能补上一两个模糊的知识点,也算有点进步吧。
1.简述变量声明和定义的区别。
为变量分配地址和存储空间的称为定义,不分配地址的称为声明。一个变量可以在多个地方声明,但是只在一个地方定义。加入extern修饰的是变量的声明,说明此变量将在文件以外或在文件后面部分定义。
2.简述sizeof和strlen的区别
最常考察的题目之一。主要区别如下:
1)sizeof是一个操作符,strlen是库函数。
2)sizeof的参数可以是数据的类型,也可以是变量,而strlen只能以结尾为‘\0‘的字符串作参数。
3)编译器在编译时就计算出了sizeof的结果。而strlen 函数必须在运行时才能计算出来。并且sizeof计算的是数据类型占内存的大小,而strlen计算的是字符串实际的长度。
4)数组做sizeof的参数不退化,传递给strlen就退化为指针了。
3.说说C和C++中的static有什么作用
这个真的在面试的时候被问过。
在C中static用来修饰局部静态变量和外部静态变量、函数。而C++中除了上述功能外,还用来定义类的成员变量和函数。即静态成员和静态成员函数。编程时最常用的是static的记忆性,和全局性的特点可以让在不同时期调用的函数进行通信,传递信息,而C++的静态成员则可以在多个对象实例间进行通信,传递信息。
4.C和C++中动态内存分配有什么方法,有何区别
C里面一般用malloc/free,C++可用malloc/free和new/delete。区别见找工作笔试面试那些事儿(3)---内存管理那些事中的内容。
5.简述C、C++程序编译的内存分配情况
之前提过,主要有静态存储区分配,在堆上和栈上分配三种,具体场景见找工作笔试面试那些事儿(3)---内存管理那些事中的内容。
6.说说strcpy、sprintf与memcpy三个函数
三个函数的功能分别为:
strcpy:实现字符串变量间的拷贝
sprintf:主要实现其他数据类型格式到字符串的转化
Memcpy:主要是内存块间的拷贝
它们的区别有:
(1)操作对象不同,strcpy的两个操作对象均为字符串,sprintf的操作源对象可以是多种数据类型,目的操作对象是字符串,memcpy 的两个对象就是两个任意可操作的内存地址,并不限于何种数据类型。
(2)执行效率不同,memcpy最高,strcpy次之,sprintf的效率最低。
7.说说拷贝构造函数和赋值运算符
拷贝构造函数和赋值运算符有以下两个不同之处:
(1)拷贝构造函数生成新的类对象,而赋值运算符不能。
(2)由于拷贝构造函数是直接构造一个新的类对象,所以在初始化这个对象之前不用检验源对象是否和新建对象相同。而赋值运算符则需要这个操作,另外赋值运算中如果原来的对象中有内存分配要先把内存释放掉(这一点在之前找工作笔试面试那些事儿(5)---构造函数、析构函数和赋值函数中提到了)。
8.简述类成员函数的重写、重载和隐藏的区别
见找工作笔试面试那些事儿(4)---C++函数高级特征中所述。
9.用递归和非递归两种方法翻转一个链表
先定义一下链表:
[cpp] view plaincopy
typedef struct node
{
ElemType data;
struct node * next;
}ListNode;
typedef struct
{
ListNode *head;
int size;
ListNode *tail;
}List;
/*********************************************************
非递归的翻转实际上就是使用循环,依次后移指针,
并将遇到的链表指针反转
*********************************************************/
void ReserveList(List * plist) //非递归实现,
{
ListNode * phead; //新链表的头 开始的第一个节点
ListNode * pt; //旧链表的头 开始的第二个节点
ListNode * pn; //旧链表头的下一个
phead = plist->head;
if(phead && phead->next&& phead->next->next) //首先确定
{
phead = plist->head->next; //新链表就是以第一个节点开始,依次在表头添加节点,添加的节点是旧链表的第一个节点
pt = phead->next; //旧链表,旧链表被取走头结点之后放入新链表的表头,
pn = pt->next;
phead->next = 0;
while(pt)
{
pn = pt->next; //pn是旧链表的第二个节点
pt ->next = phead; //取旧链表的第一个节点插入新链表
phead = pt;
pt = pn; //旧链表往后移动
}
}
plist->head->next = phead; //新链表重新赋值到整个链表
}
/*********************************************************
递归思想,原理也是从就链表上依次取元素放入到新链表
直到原始链表被取完,得到新链表
*********************************************************/
ListNode * ReserveListRe(ListNode * oldlist,ListNode * newlist)
{
ListNode * pt;
pt = oldlist->next; //取旧链表的表头,pt是现在的旧链表
oldlist->next = newlist; //就旧链表插入到新链表
newlist = oldlist; //如果旧链表是空,表示旧链表被取完了,新链表就是翻转之后的链表
return (pt == NULL) ? newlist : ReserveListRe(pt,newlist);
}
10.谈谈对C++的引用和C语言的指针的认识
简单说来,引用即别名,指针即地址。具体的部分参见找工作笔试面试那些事儿(2)---函数那些事中的“关于指针和引用”。
重点谈一下它们的区别吧:
(1)引用必须被初始化,但是不分配存储空间。指针不声明时初始化,在初始化的时候需要分配存储空间。
(2)引用初始化以后不能被改变,指针可以改变所指的对象。
(3)不存在指向空值的引用,但是存在指向空值的指针。
11.简述指针常量与常量指针区别
这是一个常见的问题。也就是const char *p和char * const p的差别,前者称为常量指针(指针指向的内容不可变),后者是指针常量(指针本身不可再被重新赋值)。下面是一个比较好记的方法,根据const的位置确定其修饰的内容:
const char* p : 因为const 修饰符在 * 号前面,因此const 修饰的是 (*p),因此p指向的字符串是const的.
char const* p : 等价于const char* p, 因为const 修饰符在 * 号前面,因此const 修饰的是 (*p),因此p指向的字符串是const的.
char* const p: const修饰的是变量p,而变量p是 char* 类型的,所以这个char* 变量本省是const,它的值初始化后就不能变了.
12.数组名和指针的区别
指针是一个变量,有自己对应的存储空间,而数组名仅仅是一个符号,不是变量,因而没有自己对应的存储空间。
1、地址相同,大小不同
示例代码:
[cpp] view plaincopy
int arr[10];
int* p=arr;
cout<
cout<
cout<<sizeof(arr)< cout<<sizeof(p)< 2、都可以用指针作为形参 示例程序: [cpp] view plaincopy void fun(int* p) { cout<
} int main() { int arr[10]={0}; int* p=arr; fun(arr); return 0; } 3、指针可以自加,数组名不可以 4、作为参数的数组名的大小和指针的大小相同 13.构造函数能否为虚函数,为什么? 构造函数不能是虚函数。而且不能在构造函数中调用虚函数,因为那样实际执行的是父类的对应函数,因为自己还没有构造好。析构函数可以是虚函数,而且,在一个复杂类结构中,这往往是必须的。析构函数也可以是纯虚函数,但纯虚析构函数必须有定义体,因为析构函数的调用是在子类中隐含的。 虚函数的动态绑定特性是实现重载的关键技术,动态绑定根据实际的调用情况查询相应类的虚函数表,调用相应的虚函数。 14.谈谈你对面向对象的认识 说实话,这种开放式的题目实则挺考察对知识的深层把握程度的。 面向对象可以理解成对待每一个问题,都是首先要确定这个问题由几个部分组成,而每一个部分其实就是一个对象。然后再分别设计这些对象,最后得到整个程序。传统的程序设计多是基于功能的思想来进行考虑和设计的,而面向对象的程序设计则是基于对象的角度来考虑问题。这样做能够使得程序更加的简洁清晰。 编程中接触最多的“面向对象编程技术”仅仅是面向对象技术中的一个组成部分。发挥面向对象技术的优势是一个综合的技术问题,不仅需要面向对象的分析,设计和编程技术,而且需要借助必要的建模和开发工具。 15.delete 与 delete []有什么区别? 这个特别在找工作笔试面试那些事儿(3)---内存管理那些事中提到了,简单说来,delete[]删除一个数组,delete 删除一个指针。 16.写个小程序确定一个数转化成二进制后是1的位的个数 很久以前就开始流传的一道微软面试题。 [cpp] view plaincopy int func(x) { int countx = 0; while(x) { countx ++; x = x&(x-1); } return countx; } 17.将“引用”作为函数返回值类型的格式、好处和需要遵守的规则? 格式:类型标识符&函数名(形参列表及类型说明){ //函数体} 好处:在内存中不产生被返回值的副本;(注意:正是因为这点原因,所以返回一个局部变量的引用是不可取的。因为随着该局部变量生存期的结束,相应的引用也会失效,产生 runtime error!) 注意事项: (1)不能返回局部变量的引用。 主要原因是局部变量会在函数返回后被销毁,因此被返回的引用就成为了"无所指"的引用,程序会进入未知状态。 (2)不能返回函数内部new分配的内存的引用。 虽然不存在局部变量的被动销毁问题,可对于这种情况(返回函数内部new分配内存的引用),又面临其它尴尬局面。例如,被函数返回的引用只是作为一个临时变量出现,而没有被赋予一个实际的变量,那么这个引用所指向的空间(由new分配)就无法释放,造成内存泄露。 (3)可以返回类成员的引用,但最好是const。 (4)流操作符重载返回值申明为“引用”的作用: 流操作符<<和>>,这两个操作符常常希望被连续使用,例如:cout << "hello" << endl; 因此这两个操作符的返回值应该是一个仍然支持这两个操作符的流引用。 (5)在另外的一些操作符中,却千万不能返回引用:+-*/ 四则运算符。它们不能返回引用。 主要原因是这四个操作符没有side effect,因此,它们必须构造一个对象作为返回值,可选的方案包括:返回一个对象、返回一个局部变量的引用,返回一个new分配的对象的引用、返回一个静态对象引用。 18.谈谈对于关联、聚合(Aggregation)以及组合(Composition)的认识 涉及到UML中的一些概念: 关联是表示两个类的一般性联系,比如“学生”和“老师”就是一种关联关系; 聚合表示has-a的关系,是一种相对松散的关系,聚合类不需要对被聚合类负责,用空的菱形表示聚合关系:从实现的角度讲,聚合可以表示为: class A {...} class B { A* a; .....} 组合表示contains-a的关系,关联性强于聚合:组合类与被组合类有相同的生命周期,组合类要对被组合类负责,采用实心的菱形表示组合关系:实现的形式是: class A{...} class B{ A a; ...} 19.当一个类C 中没有任何成员变量与成员函数,这时sizeof(C)的值是多少。如果不是零,请解释一下编译器为什么没有让它为零。 一个空类对象的大小是1byte。这是被编译器安插进去的一个字节,这样就使得这个空类的两个实例得以在内存中配置独一无二的地址。 20.用变量a给出下面的定义 a) 一个整型数(An integer) b) 一个指向整型数的指针(A pointer to an integer) c) 一个指向指针的的指针,它指向的指针是指向一个整型数(A pointer to a pointer to an integer) d) 一个有10个整型数的数组(An array of 10 integers) e) 一个有10个指针的数组,该指针是指向一个整型数的(An array of 10 pointers to integers) f) 一个指向有10个整型数数组的指针(A pointer to an array of 10 integers) g) 一个指向函数的指针,该函数有一个整型参数并返回一个整型数(A pointer to a function that takes an integer as an argument and returns an integer) h) 一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型 数( An array of ten pointers to functions that take an integer argument and return an integer ) 非常非常经典的一道题,很多笔试面试题是从上述a-h中的一个或者几个,答案如下: a) int a; // An integer b) int *a; // A pointer to an integer c) int **a; // A pointer to a pointer to an integer d) int a[10]; // An array of 10 integers e) int *a[10]; // An array of 10 pointers to integers f) int (*a)[10]; // A pointer to an array of 10 integers g) int (*a)(int); // A pointer to a function a that takes an integer argument and returns an integer h) int (*a[10])(int); // An array of 10 pointers to functions that take an integer argument and return an integer 21.成员函数通过什么来区分不同对象的成员数据?为什么它能够区分? 通过this指针来区分的, 因为它指向的是对象的首地址。 22.拷贝构造函数在哪几种情况下会被调用? 1).当类的一个对象去初始化该类的另一个对象时; 2).如果函数的形参是类的对象,调用函数进行形参和实参结合时; 3).如果函数的返回值是类对象,函数调用完成返回时。 23. 流运算符为什么不能通过类的成员函数重载?一般怎么解决? 因为通过类的成员函数重载必须是运算符的第一个是自己,而对流运算的重载要求第一个参数是流对象。一般通过友元来解决。 24. 虚拟函数与普通成员函数的区别?内联函数和构造函数能否为虚拟函数? 区别:虚拟函数有virtual关键字,有虚拟指针和虚函数表,虚拟指针就是虚拟函数的接口,而普通成员函数没有。内联函数和构造函数不能为虚拟函数。