19 Mar 2016

说说那些iOS笔试题

博主之前从事嵌入式开发,本科专业软件工程。毕业后一直从事嵌入式C语言。之所以进入嵌入式行业,完全是个人兴趣。不过,在从业两年之后发现不是自己喜欢的菜。毅然决然的转型到iOS行业。然,博主并非参加培训学校出来,完全利用工作之余时间自学,现在已经在ZAKER工作,从事ZAKER客户端的iPhone版本开发。这里,博主分享一下之前找工作时,总结的笔试题。

题目与答案

答案仅供参考,如有异议或者错误,请指正。

中文试题

  • #import 跟#include、@class有什么区别?#import<>跟 #import""又什么区别?
1) #import和#include都能完整地包含某个文件的内容,#import能防止同一个文件被包含多次
2) @class仅仅是声明一个类名,并不会包含类的完整声明;@class还能解决循环包含的问题
3) #import <>用来包含系统自带的文件,#import “”用来包含自定义的文件
  • 属性readwrite,readonly,assign,retain,copy,nonatomic各是什么作用,在那种情况下用?
readwrite:同时生成get方法和set方法的声明和实现
readonly:只生成get方法的声明和实现
assign:set方法的实现是直接赋值,用于基本数据类型
retain:set方法的实现是release旧值,retain新值,用于OC对象类型
copy:set方法的实现是release旧值,copy新值,用于NSString、block等类型
nonatomic:非原子性,set方法的实现不加锁(比atomic性能高)
  • 写一个setter方法用于完成@property nonatomic,retainNSString *name,写一个setter方法用于完成@propertynonatomiccopyNSString *name.
@property (nonatomic, retain) NSString *name;
- (void)setName:(NSString *)name
{
	if (_name != name) {
		[_name release];
		_name = [name retain];
}
}
@property(nonatomic, copy) NSString *name;
- (void)setName:(NSString *)name
{
	if (_name != name) {
		[_name release];
		_name = [name copy];
}
}
  • 对于语句NSString*obj = [[NSData alloc] init]; ,编译时和运行时obj分别是什么类型?
编译时是NSString类型
运行时是NSData类型
  • 常见的object-c的数据类型有那些,和C的基本数据类型有什么区别?
常用OC类型:NSString、NSArray、NSDictionary、NSData、NSNumber等
OC对象需要手动管理内存,C的基本数据类型不需要管理内存
  • id 声明的变量有什么特性?
id声明的变量能指向任何OC对象
  • Objective-C如何对内存管理的,说说你的看法和解决方法?
每个对象都有一个引用计数器,每个新对象的计数器是1,当对象的计数器减为0时,就会被销毁
通过retain可以让对象的计数器+1、release可以让对象的计数器-1
还可以通过autorelease pool管理内存
如果用ARC,编译器会自动生成管理内存的代码
  • 内存管理的几条原则时什么?按照默认法则.哪些方法生成的对象需要手动释放?在和property结合的时候怎样有效的避免内存泄露?
只要调用了alloc、copy、new方法产生了一个新对象,都必须在最后调用一次release或者autorelease
只要调用了retain,都必须在最后调用一次release或者autorelease
@property如果用了copy或者retian,就需要对不再使用的属性做一次release操作
如果用了ARC,另外讨论.
  • 看下面的程序,三次NSLog会输出什么?为什么?
NSMutableArray* ary = [[NSMutableArray array] retain];  
NSString *str = [NSString stringWithFormat:@"test"];  // 1 
[strretain];   // 2
[aryaddObject:str]; // 3  
NSLog(@"%d",[str retainCount]);  
[strretain];  // 4
[strrelease];   // 3
[strrelease];   // 2
NSLog(@"%d",[str retainCount]);  
[aryremoveAllObjects]; // 1  
NSLog(@"%d",[str retainCount]);

   结果:3、2、1

  • OC中创建线程的方法是什么?如果指定在主线程中执行代码?如何延时执行代码?
创建线程的方法
NSThread
NSOperationQueue和NSOperation
GCD
主线程中执行代码
[self performSelectorOnMainThread: withObject: waitUntilDone:];
[self performSelector: onThread:[NSThreadmainThread] withObject: waitUntilDone:];
dispatch_async(dispatch_get_main_queue(), ^{
});
延时执行
double delayInSeconds = 2.0;
dispatch_time_tpopTime = dispatch_time(DISPATCH_TIME_NOW, 
(int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){        
});
[self performSelector: withObject: afterDelay:];
[NSTimer scheduledTimerWithTimeInterval: target: selector: userInfo: repeats:];

英文试题

提示: 一定要把英文题目过一遍,有些公司的题目故意弄成英文的。

  • Difference between shallow copy and deep copy?
浅拷贝:指针(地址)拷贝,不会产生新对象
深拷贝:内容拷贝,会产生新对象
  • What is advantage of categories? What is difference between implementing a category and inheritance?
分类可以在不修改原来类模型的基础上拓充方法
分类只能扩充方法、不能扩充成员变量;继承可以扩充方法和成员变量
继承会产生新的类
  • Difference between categories and extensions?
分类是有名称的,类扩展没有名称
分类只能扩充方法、不能扩充成员变量;类扩展可以扩充方法和成员变量
类扩展一般就写在.m文件中,用来扩充私有的方法和成员变量(属性)
  • Difference between protocol in objective c and interfaces in java?
Java的接口中声明的方法必须都实现
Oc的protocol中声明的方法并不一定要实现
  • What are KVO and KVC?
KVC是键值编码,可以通过一个字符串的key(属性名)修改对象的属性值
KVO是键值监听,可以监听一个对象属性值的改变
  • What is purpose of delegates?
两个对象之间传递数据和消息
解耦,拆分业务逻辑
  • What are mutable and immutable types in Objective C?
mutable是可变类型,比如NSMutableArray,可以动态往里面添加元素
immutable是不可变类型,比如NSArray,固定的存储空间,不能添加元素
  • When we call objective c is runtime language what does it mean?
动态绑定:对象类型在运行时才真正确定
多态性
消息机制
  • what is difference between NSNotification and protocol?
通过NSNotification可以给多个对象传递数据和消息
通过protocol(代理模式)只能给一个对象传递数据和消息
  • What is push notification?
本地推送:程序内部弹出通知到用户设备
远程推送:由推送服务器推送通知到用户设备
  • What is Polymorphism?
多态:父类指针指向子类对象
  • What is Singleton?
单例:保证程序运行过程中,永远只有一个对象实例
目的是:全局共享一份资源、节省不必要的内存开销
  • What is responder chain?
响应者链:
UIResponder有一个nextResponder属性,通过该属性可以组成一个响应者链,事件或消息在其路径上进行传递
如果UIResponder没有处理传给它的事件,会将未处理的消息转发给自己的nextResponder

响应链

  • Difference between frame and bounds?
frame以父控件的左上角为坐标原点
bounds以控件本身的左上角为坐标原点
  • Difference between method and selector?
通过一个selector可以找到方法地址,进而调用一个方法
  • Is there any garbage collection mechanism in Objective C.?
OC 1.0没有垃圾回收
OC 2.0有垃圾回收,只能用在Mac上
iOS中有ARC机制,是编译器特性,垃圾回收是运行时特性
  • What is NSOperation queue?
用来存放NSOperation对象的队列,可以用来异步执行一些操作
一般可以用在网络请求等耗时操作
  • Can we use one tableview with two different datasources? How you will achieve this?
从对象属性上分析,tableView只有一个dataSource属性。当然,真要使用两个不同的数据源,还是有其他办法解决的
  • Can we use two tableview controllers on one viewcontroller?
从技术角度上分析,一个控制器内部添加两个表格控制器是没有问题的
  • What is lazy loading?
延迟加载:比如控制器的view,在第一次用到view时才会调用loadView方法进行创建
  • 链表不具备的特点是()

A. 可随机访问任何一个元素

B. 插入,删除操作不需要移动元素

C. 无需事先估计存储空间大小

D. 所欲存储空间可以是不连续的

参考答案: (A) 链表不同于数组。链表之所有叫链表,就是像一条链一样,要过到某个节点处,就得遍历着找;而数组才具备随机访问任何一个元素的能力,数组可以通过索引直接访问元素,时间复杂度为常量,效率非常高,因此在某些场合上,我们需要数组这样的数据结构。

B. 链表的插入、删除都不需要移动元素,只需要修改指针的指向就可以了,因为链表上的每个节点都是动态分配的,分配在堆上,通过指针来指向每个节点的内存区,要获取某个节点的值,是需要遍历一遍才能找到对应的节点的。

C. 因为链表上的每个节点是分配在堆上,需要开发人员手动申请内存空间的,因此不像数组在定义时就要指定存储空间大小。对于链表,需要增加一个节点时,直接在堆上申请。当需要删除某个节点时,可以直接将该节点的内存给释放掉。

D. 因为链接中的节点都是存储在堆上的,而每个节点之间都有一个指向前一个节点和后一个节点的指针,只要知道链表头指针,就可以通过遍历查找到任何一个节点。因此,链表不同于数组,数组是要连续的内存存储空间,才能保证以常量时间复杂度快速访问任意元素;而链表不要求每个节点是连接,在堆上申请的内存空间很难得到连续的,而且空间产生内存碎片。

  • 关于多线程和多进程编程,下面描述正确的是()

A. 多进程里,子进程可获取父进程的所有堆和栈的数据;而线程会与同进程的其他线程共享数据,拥有自己的栈空间。

B. 线程因为有自己的独立栈空间且共享数据,所有执行的开销相对较大,同时不利于资源管理和保护。

C. 线程的通信速度更快,切换更快,因为他们在同一地址空间内。

D. 线程使用公共变量/内存时需要使用同步机制,因为他们在同一地址空间内。

  • 设两个变量a=19;b=29;在不创建新实例的情况下使a、b的值互换?

参考答案:

这道题要求不创建新的实例,只有a、b两个变量,要交换这两个变量的值,通常的做法是使用临时变量来临时存储,但是现在要求不使用新的实例,那么有什么办法呢?

方法就是通过位运算来操作:

a = a ^ b;
b = a ^ b;
a = a ^ b;

对于题目中的a = 19,也就是对应二进制00010011;而b=29,也就是对应二进制00011101

第一步:a = 00010011 ^ 00011101 => 00001110,将a、b的值都记录下来了

第二步:b = 00001110 ^ 00011101 => 00010011(值为19,也就是b得到了原来的a的值)

第三步:a = 00001110 ^ 00010011 => 00011101 (值为29,也就是a得到了原来的b的值)

注意,符号表示按位异或。所谓按位异或是指对应位置上的二进制数值相同为0,不同为1。

  • 使用block时什么情况会发生引用循环,如何解决?

参考答案:http://www.henishuo.com/ios-block-memory-cycle

  • 为什么要序列化,对象序列化方式?

参考答案:

将对象JSON序列化:

NSLog(@"%s", __FUNCTION__);
NSDictionary *dict = @{@"key"  : @"value",
                     @"key1" : @"value1",
                     @"key2" : @"value2"};
NSData *data = [NSJSONSerialization dataWithJSONObject:dict options:NSJSONWritingPrettyPrinted error:nil];
NSLog(@"%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);

将对象归档:需要遵守NSCoding协议,实现如下方法:

- (void)encodeWithCoder:(NSCoder *)aCoder {
  [aCoder encodeObject:self.title forKey:@"title"];
}
  • 简述如何处理UI与耗时操作的通信,有哪些方式及各自的优缺点?

参考答案:

1)将耗时的计算和IO操作放在子线程去处理,然后到主线程更新UI。优点是采用预加载方式,将耗时操作提前处理。优点是可让UI更流畅;缺点是内存会增多,控制加载逻辑比较复杂。

2)采用延迟加载方式,将耗时操作而不立刻使用时,采用延迟加载。优点是界面可提高流畅度;缺点是在需要显示时还需要加载才能显示,需要稍稍等待。

  • 如何优化一个TableView?

参考答案:

1)若高度一定,直接使用rowHeight属性而不是使用heightForRowAtIndexPath方法,以减少调用的消耗。若高度是不固定的,heightForRowAtIndexPath所计算的高度应该缓存起来,每次数据源发生变化时,比如删除、插入、更新行都会重新请求所有的高度。若有100个行,就会有调用100次,因为将高度缓存起来是应该的。同理,heightForHeaderInSection、heightForFooterInSection也应该缓存起来。

2)不要在tableView:cellForRowAtIndexPath:中做太多的计算和IO操作,比如可以将需要的计算提前计算好、IO操作也提前计算好。它应该直接调用来显示就可以。

3)将计算行高的时间提前到从服务器获取数据的时候,计算完了高度一并写回数据库或者通过转型为model,将高度放到模型中。但是,最好将高度缓存起来。若一个model的数据有不同的状态,比如展开与收起状态,应该也将高度都缓存起来。注意使用异步去计算,计算完成后再回到主线程显示。

4)在设置显示图片时,不要直接设置UIImageView的contentMode属性自动适应,图片变形会计算transform,压缩时会乘以一个矩阵,消耗性能。对于要求性能较高的app,应该将得到的图片经过处理成UIImageView大小后再呈现。

5)不要将视图的opaque属性设置为NO,默认为YES,它表示不透明度。当opque为NO的时候,图层的半透明取决于图片和其本身合成的图层为结果。

6)layer添加圆角是比较耗时的,这样会离屏渲染,需要牺牲更多的性能。比如,图片显示有圆角时,可以通过core graphics来生成带圆角的图片等。

7)手动绘制cell。绘制cell不建议使用UIView,建议使用CALayer。 UIView的绘制是建立在CoreGraphic上的,其使用的是CPU。CALayer使用的是Core Animation,CPU、GPU都可以使用且由系统自动决定使用哪一个。UIView的绘制,使用的是自下向上的一层一层的绘制,而后渲染。Layer处理的是纹理,利用GPU的 Texture Cache和独立的浮点数计算单元可以加速纹理的处理。

8)重用cell。防止重复的绘制,减少渲染次数,可提高性能。

9)减少subviews的数量。尽量放在同一层view上显示。

10)尽量少动态给cell添加子view。用addView给Cell动态添加View,可以初始化时就添加,然后通过hide来控制是否显示。

更多参看: http://blog.ibireme.com/2015/11/12/smooth_user_interfaces_for_ios/

简答题

  • 假设类SomeClass中声明了一个委托属性delegate,该属性遵守自定义委托协议SomeDelegate,请写出该类和对应委托协议的定义?
@protocol SomeDelegate<NSObject>
@required //必须要实现的方法
@optional //可选实现的方法
@end
@interface SomeClass
@property (nonatomic, assign)id <SomeDelegate> delegate;
@end
  • 简述UITableView的重用机制,并写出实现该机制的关键代码?

关键代码:

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cellId"];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cellId"];
    }
  • 简述推送实现步骤?

  • 定义一个带参宏,返回两个参数中较小的那个?

  • strong和weak分别起什么作用?有什么区别?

  • 执行下面程序后NSLog的输出结果为( C )?

A.1,1 B.2,1 C.2,5 D.运行错误

int a[5] = {1,2,3,4,5};
int *ptr = (int *)(&a+1);
NSLog(@“%d,%d”, *(a+1), *(ptr-1));
  • 执行下面程序后NSLog的输出结果为( B )?

A.a,a1,a1 B.a1,a1,a1 C.a1,a,a D.a1,a1,a

int main(int argc, char *argv[]){
    NSArray *mArray1 = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"], @"b", @"c", nil];
        NSArray *mArrayCopy2 = [mArray1 copy];
        NSMutableArray *mArrayMCopy1 = [mArray1 mutableCopy];
        NSMutableString *testString = [mArray1 objectAtIndex:0];
        [testString appendString:@"1"];
        NSLog(@"%@,%@,%@", [mArray1 objectAtIndex:0],[mArrayCopy2 objectAtIndex:0],[mArrayMCopy1 objectAtIndex:0]);
    return 0;
}
  • Cocoa中所有的类都是( NSObject和NSProxy )的子类。

  • 列举几个Cocoa Touch框架?

Foundation、UIKit、Core Data

  • 下面机型屏幕分辨率分别是多少?
iPhone4、4S:960X640
iPhone5、5S、5C:1136X640
iPhone6:375X667
iPhone6 Plus:414X736
iPad mini:1024X768
iPad mini 2:2048X1536
iPad Air:2048X1536
iPad Air 2:2048X1536
  • Objective-C中的线程类是( NSThread ),常见方法有哪些( dispatch_async )、( dispatch_sync ),处理多线程同步有哪些类( )。

数据库

现有MySQL数据库,分别对下表写出要求的SQL语句,用到实例数据请自行给出即可。

表结构如下:

字段名 类型
UserID Integer
UserName varchar(20)
Password varchar(20)

创建表:

CREATE  TABLE `test`.`table_a` (
  `UserID` INT NOT NULL ,
  `UserName` VARCHAR(20) NULL ,
  `Password` VARCHAR(20) NULL ,
  PRIMARY KEY (`UserID`) );

增加记录:

insert into `test`.`table_a` ( `UserName`, `UserID`, `Password`) values ( 'cd', '10', '123')

删除记录:

delete from `test`.`table_a` where `UserID`=’10'
修改记录:update `test`.`table_a` set `Password`='12346' where `UserID`='10' 

编程题

1.请通过接口“http://someurl/somefunc”获取数据,并在UI上显示。接口入参argu是一个字符串类型的变量,返回值是字典。

1)使用NSURL相关API实现网络加载类,其中:通过post方法发送请求,建立异步连接;

2)报文采用JSON格式;

3)多线程采用GCD或NSOperation实现;

4)以左边键右边值的格式在界面上显示结果。

2.传入数组*array和数组长度length,实现冒泡排序算法。

int *BubbleSort(int *array, int length);

int *BubbleSort(int *array, int length) {
    int i = 0, j = 0, temp = 0;
    if (NULL == array) {
        return NULL;
    }
    for (i = 0; i < length; i++) {
        for (j = i; j < length; j++) {
            if (*(array + i) > *(array + j)) {
                temp = *(array + i);
                *(array + i) = *(array + j);
                *(array + j) = temp;
            }
        }
    }
    return array;
}