iOS面试题汇总(基础篇一)
1. 比较以下关键词的区别:strong, weak, assign, copy
strong
:修饰的对象引用计数会增加1,该对象只要引用计数不为0则不会被销毁,所以将其设为nil引用计数归0可以销毁它。
weak
:仅指向对象,其修饰的对象引用计数不会增加。该对象引用计数归0时会自行在内存中销毁。
assign
:主要用于修饰基本数据类型,如NSInteger和CGFloat,这些数值主要存在于栈上。
weak与assign区别
: weak一般用来修饰对象,assign一般用来修饰基本数据类型。原因是assign修饰的对象被释放后,指针的地址依然存在,造成野指针,在堆上容易造成崩溃。而基本数据类型在栈上,系统会自动处理其上内存,不会造成野指针。
copy
:copy的复制每次会在内存中拷贝一份对象,指针指向拷贝得来对象的地址,不对原对象造成影响且无关系。一般用在修饰有可变对应类型的不可变对象上,如NSString, NSArray, NSDictionary。
注
:Objective-C 中,基本数据类型的默认关键字是atomic, readwrite, assign;普通属性的默认关键字是atomic, readwrite, strong。基本数据类型主要存在于栈上,对象存在于堆上。
2. 比较以下关键词的区别:__weak,__block
__weak
:与weak基本相同,前者用于修饰变量(variable),后者用于修饰属性(property)。__weak 主要用于防止block中的循环引用。
__block
:同样用于修饰变量,它是引用修饰,所以其修饰的值是动态变化的,即可以被重新赋值的。__block用于修饰某些block内部将要修改的外部变量。
注
:__weak和__block的使用场景几乎与block息息相关。而所谓block,就是Objective-C对于闭包的实现。闭包就是没有名字的函数,或者理解为指向函数的指针。
3. 比较以下关键词的区别:atomatic, nonatomic
atomic
:修饰的对象会保证setter和getter的完整性,任何线程对其访问都可以得到一个完整的初始化后的对象。因为要保证操作完成,所以速度慢。它比nonatomic安全,但也并不是绝对的线程安全,例如多个线程同时调用set和get就会导致获得的对象值不一样。绝对的线程安全就要用关键词synchronized。
nonatomic
:修饰的对象不保证setter和getter的完整性,所以多个线程对它进行访问,它可能会返回未初始化的对象。正因为如此,它比atomic快,但也是线程不安全的。
4. 找出下面代码错误
UILabel *alertLabel = [[UILabel alloc] initWithFrame:CGRectMake(100,100,100,100)];
alertLabel.text = @"Wait 4 seconds...";
[self.view addSubview:alertLabel];
NSOperationQueue *backgroundQueue = [[NSOperationQueue alloc] init];
[backgroundQueue addOperationWithBlock:^{
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:4]];
alertLabel.text = @"Ready to go!";
}];
所有UI的相关操作应该在主线程进行,正确代码入下:
UILabel *alertLabel = [[UILabel alloc] initWithFrame:CGRectMake(100,100,100,100)];
alertLabel.text = @"Wait 4 seconds...";
[self.view addSubview:alertLabel];
NSOperationQueue *backgroundQueue = [[NSOperationQueue alloc] init];
[backgroundQueue addOperationWithBlock:^{
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:4]];
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
alertLabel.text = @"Ready to go!";
}];
}];
5. 以scheduledTimerWithTimeInterval的方式触发的timer,在滑动页面上的列表时,timer会暂停,为什么?该如何解决?
原因:在于滑动时当前线程的runloop切换了mode用于列表滑动,导致timer暂停。
runloop中的mode主要用来指定事件在runloop中的优先级,有以下几种:
- Default(NSDefaultRunLoopMode):默认,一般情况下使用;
- Connection(NSConnectionReplyMode):一般系统用来处理NSConnection相关事件,开发者一般用不到;
- Modal(NSModalPanelRunLoopMode):处理modal panels事件;
- Event Tracking(NSEventTrackingRunLoopMode):用于处理拖拽和用户交互的模式。
- Common(NSRunloopCommonModes):模式合集。默认包括Default,Modal,Event Tracking三大模式,可以处理几乎所有事件。
回到题中的情境。滑动列表时,runloop的mode由原来的Default模式切换到了Event Tracking模式,timer原来好好的运行在Default模式中,被关闭后自然就停止工作了。
解决方法:其一是将timer加入到NSRunloopCommonModes中。其二是将timer放到另一个线程中,然后开启另一个线程的runloop,这样可以保证与主线程互不干扰,而现在主线程正在处理页面滑动。示例代码如下:
// 方法1
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
// 方法2
dispatch_async(dispatch_get_global_queue(0, 0), ^{
timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(repeat:) userInfo:nil repeats:true];
[[NSRunLoop currentRunLoop] run];
});
6. 写一条sql语句,查询出所在省以“湖”开头,邮编为“436001”的城市?
SELECT * FROM t_citys WHERE postcode = '%@' AND province LIKE '湖%%'
7. 用预处理指令#define声明一个常数,用以表明1年中有多少秒?(忽略闰年问题)
#define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL, UL(表示无符号长整型)
8. 写一个宏MIN ,实现输入两个参数并返回较小的一个的功能
#define MIN(A,B) ((A) <= (B) ? (A) : (B))
,不需要用if else
。
副作用:least = MIN(*p++, b);
此时转化如下:((*p++) <= (b) ? (*p++) :(b))
,*p++会影响返回值的准确性。
9. static的作用
- 函数体内static 变量的作用范围为该函数体,不同于 auto 变量,该变量的内存只被分配一次,因此其值在下次调用时仍维持上次的值;
- 在模块内的static 全局变量可以被模块内所用函数访问,但不能被模块外其它函数访问;
- 在模块内的static函数只可被这一模块内的其它函数调用,这个函数的使用范围被限制在声明它的模块内;
- 在类中的static成员变量属于整个类所拥有,对类的所有对象只有一份拷贝;
- 在类中的static 成员函数属于整个类所拥有,这个函数不接收 this 指针,因而只能访问类的static 成员变量。
10. 简述内存分区情况
- 代码区:存放函数二进制代码。
- 数据区:系统运行时申请内存并初始化,系统退出时由系统释放。 存放全局变量、静态变量、常量。
- 堆区:通过malloc等函数或new等操作符动态申请得到,需程序员手动申请和释放。
- 栈区:函数模块内申请,函数结束时由系统自动释放。存放局部变量、函数参数。
11. #include<filename>和#include”filename”有什么区别
- #include<filename>:直接在库文件目录中搜索所包含的文件;
- #include”filename”:在当前目录下搜索所包含的文件,如果没有的话再到库文件目录搜索。
12. 写出const char * p; char const * p; char * const p; const char * const p;
的区别?
-
const char * p
:定义一个指向字符常数的指针,p可变,*p不可变。 -
char const * p
:同上。 -
char * const p
:定义一个指向字符的指针常数,*p可变,p不可变。 -
const char * const p
:定义一个指向字符常数的指针常数,*p、p均不可变。
13. UIView与CLayer有什么区别?
- UIView 是 iOS 系统中界面元素的基础,所有的界面元素都是继承自它。它本身完全是由 CoreAnimation 来实现的。它真正的绘图部分,是由一个 CALayer 类来管理。 UIView 本身更像是一个 CALayer 的管理器,访问它的跟绘图和跟坐标有关的属性。
- UIView 有个重要属性 layer ,可以返回它的主 CALayer 实例。