面试题

1、retain 和 copy各自的set方法

当用copy时,set方法会先release旧值,再copy一个新的对象,reference count 为1(减少了对上下文的依赖);retain,release旧值,retain新值;a ssign,直接赋值,无retain操作。retain使引用计数+1,copy是复制一个新对象
retain的set 、get方法

1
2
3
4
5
6
7
8
9
10
11
12
- (void)setAge:(NSString *)age
{
if(age != _age)
{
[_age release];
age = [_age retain];
}
}
- (NSString *)_age
{
return [[_age retain] autorelease];
}

copy的set、get方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
- (void)setNum:(NSString *)num
{
if(_num != num)
{
[_num release];
_num = [num copy];
}
}

- (NSString *)_num
{
return [[_num retain] autorelease];
}

strong 和weak的区别

weak型的指针变量仍然可以指向一个对象,但不属于对象的拥有者(指针指向对象的,当对象释放之后,weak修饰的指针指向nil)
• strong : 该属性值对应 strong 关键字,即该属性所声明的变量将成为对象的持有者,等同于”retain”
• weak : 该属性对应
weak 关键字,与 weak 定义的变量一致,该属性所声明的变量将没有对象的所有权,并且当对象被释放之后,对象将被自动赋值nil,记住IBOutlet应该使用weak
• unsafe_unretained : 等效于
unsafe_unretaind关键字声明的变量,等同于之前的”assign”,iOS 5之前的系统用该属性代替 weak 来使用
• copy : 和之前的copy一样,复制一个对象并创建strong关联
• assign : 对象不能使用assign,但原始类型(BOOL、int、float)仍然可以使用

ViewController的生命周期

1.第一次访问UIViewController的view时,view为nil,然后就会调用loadView方法创建view
2.view创建完毕后会调用viewDidLoad方法进行界面元素的初始化
3.当内存警告时,系统可能会释放UIViewController的view,将view赋值为nil,并且调用viewDidUnload方法
4.当再次访问UIViewController的view时,view已经在3中被赋值为nil,所以又会调用loadView方法重新创建view
5.view被重新创建完毕后,还是会调用viewDidLoad方法进行界面元素的初始化

iOS6.0及以上版本的内存警告:

调用didReceiveMemoryWarning内调用super的didReceiveMemoryWarning调只是释放controller的resouse,不会释放view
处理方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
-(void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];//即使没有显示在window上,也不会自动的将self.view释放。
// Add code to clean up any of your own resources that are no longer necessary.

// 此处做兼容处理需要加上ios6.0的宏开关,保证是在6.0下使用的,6.0以前屏蔽以下代码,否则会在下面使用self.view时自动加载viewDidUnLoad
if ([[UIDevice currentDevice].systemVersion floatValue] >= 6.0) {
//需要注意的是self.isViewLoaded是必不可少的,其他方式访问视图会导致它加载 ,在WWDC视频也忽视这一点。
if (self.isViewLoaded && !self.view.window)// 是否是正在使用的视图
{
// Add code to preserve data stored in the views that might be
// needed later.

// Add code to clean up other strong references to the view in
// the view hierarchy.
self.view = nil;// 目的是再次进入时能够重新加载调用viewDidLoad函数。
}
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
字符属性

字符属性可以应用于 attributed string 的文本中。

NSString *const NSFontAttributeName;(字体)

NSString *const NSParagraphStyleAttributeName;(段落)

NSString *const NSForegroundColorAttributeName;(字体颜色)

NSString *const NSBackgroundColorAttributeName;(字体背景色)

NSString *const NSLigatureAttributeName;(连字符)

NSString *const NSKernAttributeName;(字间距)

NSString *const NSStrikethroughStyleAttributeName;(删除线)

NSString *const NSUnderlineStyleAttributeName;(下划线)

NSString *const NSStrokeColorAttributeName;(边线颜色)

NSString *const NSStrokeWidthAttributeName;(边线宽度)

NSString *const NSShadowAttributeName;(阴影)(横竖排版)

NSString *const NSVerticalGlyphFormAttributeName;

常量

1> NSFontAttributeName(字体)

该属性所对应的值是一个 UIFont 对象。该属性用于改变一段文本的字体。如果不指定该属性,则默认为12-point Helvetica(Neue)。

2> NSParagraphStyleAttributeName(段落)

该属性所对应的值是一个 NSParagraphStyle 对象。该属性在一段文本上应用多个属性。如果不指定该属性,则默认为 NSParagraphStyle 的defaultParagraphStyle 方法返回的默认段落属性。

3> NSForegroundColorAttributeName(字体颜色)

该属性所对应的值是一个 UIColor 对象。该属性用于指定一段文本的字体颜色。如果不指定该属性,则默认为黑色。

4> NSBackgroundColorAttributeName(字体背景色)

该属性所对应的值是一个 UIColor 对象。该属性用于指定一段文本的背景颜色。如果不指定该属性,则默认无背景色。

5> NSLigatureAttributeName(连字符)

该属性所对应的值是一个 NSNumber 对象(整数)。连体字符是指某些连在一起的字符,它们采用单个的图元符号。0 表示没有连体字符。1 表示使用默认的连体字符。2表示使用所有连体符号。默认值为 1(注意,iOS 不支持值为 2)。

6> NSKernAttributeName(字间距)

该属性所对应的值是一个 NSNumber 对象(整数)。字母紧排指定了用于调整字距的像素点数。字母紧排的效果依赖于字体。值为 0 表示不使用字母紧排。默认值为0

7> NSStrikethroughStyleAttributeName(删除线)

该属性所对应的值是一个 NSNumber 对象(整数)。该值指定是否在文字上加上删除线,该值参考“Underline Style Attributes”。默认值是NSUnderlineStyleNone。

8> NSUnderlineStyleAttributeName(下划线)

该属性所对应的值是一个 NSNumber 对象(整数)。该值指定是否在文字上加上下划线,该值参考“Underline Style Attributes”。默认值是NSUnderlineStyleNone。

9> NSStrokeColorAttributeName(边线颜色)

该属性所对应的值是一个 UIColor 对象。如果该属性不指定(默认),则等同于 NSForegroundColorAttributeName。否则,指定为删除线或下划线颜色。更多细节见“Drawing attributedstrings that are both filled and stroked”。

10> NSStrokeWidthAttributeName(边线宽度)

该属性所对应的值是一个 NSNumber 对象(小数)。该值改变描边宽度(相对于字体size 的百分比)。默认为 0,即不改变。正数只改变描边宽度。负数同时改变文字的描边和填充宽度。例如,对于常见的空心字,这个值通常为3.0

11> NSShadowAttributeName(阴影)

该属性所对应的值是一个 NSShadow 对象。默认为 nil。

12大专栏  面试题span>> NSVerticalGlyphFormAttributeName(横竖排版)

该属性所对应的值是一个 NSNumber 对象(整数)。0 表示横排文本。1 表示竖排文本。在 iOS 中,总是使用横排文本,0 以外的值都未定义。

UIView 中的autoresizingMask的属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
在 UIView 中有一个autoresizingMask的属性,它对应的是一个枚举的值(如下),属性的意思就是自动调整子控件与父控件中间的位置,宽高。

enum {
UIViewAutoresizingNone = 0,
UIViewAutoresizingFlexibleLeftMargin = 1 << 0,
UIViewAutoresizingFlexibleWidth = 1 << 1,
UIViewAutoresizingFlexibleRightMargin = 1 << 2,
UIViewAutoresizingFlexibleTopMargin = 1 << 3,
UIViewAutoresizingFlexibleHeight = 1 << 4,
UIViewAutoresizingFlexibleBottomMargin = 1 << 5
};


UIViewAutoresizingNone就是不自动调整。
UIViewAutoresizingFlexibleLeftMargin 自动调整与superView左边的距离,保证与superView右边的距离不变。
UIViewAutoresizingFlexibleRightMargin 自动调整与superView的右边距离,保证与superView左边的距离不变。
UIViewAutoresizingFlexibleTopMargin 自动调整与superView顶部的距离,保证与superView底部的距离不变。
UIViewAutoresizingFlexibleBottomMargin 自动调整与superView底部的距离,也就是说,与superView顶部的距离不变。
UIViewAutoresizingFlexibleWidth 自动调整自己的宽度,保证与superView左边和右边的距离不变。
UIViewAutoresizingFlexibleHeight 自动调整自己的高度,保证与superView顶部和底部的距离不变。
UIViewAutoresizingFlexibleLeftMargin |UIViewAutoresizingFlexibleRightMargin 自动调整与superView左边的距离,保证与左边的距离和右边的距离和原来距左边和右边的距离的比例不变。比如原来距离为2030,调整后的距离应为68102,即68/20=102/30

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

一个对象中强引用了block,在block中又使用了该对象,就会发射循环引用。 解决方法是将该对象使用weak或者block修饰符修饰之后再在block中使用。

1
2
id weak weakSelf = self; 或者 weak __typeof(&*self)weakSelf = self该方法可以设置宏
id __block weakSelf = self;

iOS响应者链(http://www.jianshu.com/p/10a01fbea978) 以及iOS响应者链,事件的传递(http://www.jianshu.com/p/2c5678c659d5)

响应者链

1
先来说说响应者对象(Responder Object),顾名思义,指的是有响应和处理事件能力的对象。响应者链就是由一系列的响应者对象构成的一个层次结构。

UIResponder是所有响应对象的基类,在UIResponder类中定义了处理上述各种事件的接口。我们熟悉的UIApplication、 UIViewController、UIWindow和所有继承自UIView的UIKit类都直接或间接的继承自UIResponder,所以它们的实例都是可以构成响应者链的响应者对象。图一展示了响应者链的基本构成:


从中可以看到,响应者链有以下特点:

1、响应者链通常是由视图(UIView)构成的;

2、一个视图的下一个响应者是它视图控制器(UIViewController)(如果有的话),然后再转给它的父视图(Super View);

3、视图控制器(如果有的话)的下一个响应者为其管理的视图的父视图;

4、单例的窗口(UIWindow)的内容视图将指向窗口本身作为它的下一个响应者

需要指出的是,Cocoa Touch应用不像Cocoa应用,它只有一个UIWindow对象,因此整个响应者链要简单一点;

5、单例的应用(UIApplication)是一个响应者链的终点,它的下一个响应者指向nil,以结束整个循环。

响应者链 事件分发

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
第一响应者(First responder)指的是当前接受触摸的响应者对象(通常是一个UIView对象),即表示当前该对象正在与用户交互,它是响应者链的开端。整个响应者链和事件分发的使命都是找出第一响应者。

UIWindow对象以消息的形式将事件发送给第一响应者,使其有机会首先处理事件。如果第一响应者没有进行处理,系统就将事件(通过消息)传递给响应者链中的下一个响应者,看看它是否可以进行处理。

iOS系统检测到手指触摸(Touch)操作时会将其打包成一个UIEvent对象,并放入当前活动Application的事件队列,单例的UIApplication会从事件队列中取出触摸事件并传递给单例的UIWindow来处理,UIWindow对象首先会使用hitTest:withEvent:方法寻找此次Touch操作初始点所在的视图(View),即需要将触摸事件传递给其处理的视图,这个过程称之为hit-test view。

UIWindow实例对象会首先在它的内容视图上调用hitTest:withEvent:,此方法会在其视图层级结构中的每个视图上调用pointInside:withEvent:(该方法用来判断点击事件发生的位置是否处于当前视图范围内,以确定用户是不是点击了当前视图),如果pointInside:withEvent:返回YES,则继续逐级调用,直到找到touch操作发生的位置,这个视图也就是要找的hit-test view。
hitTest:withEvent:方法的处理流程如下:
首先调用当前视图的pointInside:withEvent:方法判断触摸点是否在当前视图内;
若返回NO,则hitTest:withEvent:返回nil;
若返回YES,则向当前视图的所有子视图(subviews)发送hitTest:withEvent:消息,所有子视图的遍历顺序是从最顶层视图一直到到最底层视图,即从subviews数组的末尾向前遍历,直到有子视图返回非空对象或者全部子视图遍历完毕;
若第一次有子视图返回非空对象,则hitTest:withEvent:方法返回此对象,处理结束;
如所有子视图都返回非,则hitTest:withEvent:方法返回自身(self)。


加入用户点击了View E,下面结合图二介绍hit-test view的流程:

1、A是UIWindow的根视图,因此,UIWindwo对象会首相对A进行hit-test;

2、显然用户点击的范围是在A的范围内,因此,pointInside:withEvent:返回了YES,这时会继续检查A的子视图;

3、这时候会有两个分支,B和C:

点击的范围不再B内,因此B分支的pointInside:withEvent:返回NO,对应的hitTest:withEvent:返回nil;

点击的范围在C内,即C的pointInside:withEvent:返回YES;

4、这时候有D和E两个分支:

点击的范围不再D内,因此D的pointInside:withEvent:返回NO,对应的hitTest:withEvent:返回nil;

点击的范围在E内,即E的pointInside:withEvent:返回YES,由于E没有子视图(也可以理解成对E的子视图进行hit-test时返回了nil),因此,E的hitTest:withEvent:会将E返回,再往回回溯,就是C的hitTest:withEvent:返回E--->>A的hitTest:withEvent:返回E。

至此,本次点击事件的第一响应者就通过响应者链的事件分发逻辑成功的找到了。

不难看出,这个处理流程有点类似二分搜索的思想,这样能以最快的速度,最精确地定位出能响应触摸事件的UIView。

三、说明

1、如果最终hit-test没有找到第一响应者,或者第一响应者没有处理该事件,则该事件会沿着响应者链向上回溯,如果UIWindow实例和UIApplication实例都不能处理该事件,则该事件会被丢弃;

2、hitTest:withEvent:方法将会忽略隐藏(hidden=YES)的视图,禁止用户操作(userInteractionEnabled=YES)的视图,以及alpha级别小于0.01(alpha<0.01)的视图。如果一个子视图的区域超过父视图的bound区域(父视图的clipsToBounds 属性为NO,这样超过父视图bound区域的子视图内容也会显示),那么正常情况下对子视图在父视图之外区域的触摸操作不会被识别,因为父视图的pointInside:withEvent:方法会返回NO,这样就不会继续向下遍历子视图了。当然,也可以重写pointInside:withEvent:方法来处理这种情况。

3、我们可以重写hitTest:withEvent:来达到某些特定的目的,下面的链接就是一个有趣的应用举例,当然实际应用中很少用到这些。

自定义presentViewController 动画

1
2
3
4
5
6
7
8
9
10
11
12
13

CATransition *animation = [CATransition animation];
animation.duration = 0.5;
animation.timingFunction = UIViewAnimationCurveEaseInOut;
// animation.type = @"pageCurl";
animation.type = kCATransitionMoveIn;
animation.subtype = kCATransitionFromRight;

[self.view.window.layer addAnimation:animation forKey:nil];

WSGViewController *wsgVC = [[WSGViewController alloc] init];

[self presentViewController:wsgVC animated:NO completion:nil];
1
添加一行测试的代码,下次删除
原文地址:https://www.cnblogs.com/lijianming180/p/12275739.html