|
1 |
| -#iOSInterviewQuestions |
| 1 | +#介绍 |
| 2 | +用代码编译或服务器重启的零碎时间,尝试解答网上常见的一些面试题。 |
| 3 | + |
| 4 | +###1.@property 后面可以有哪些修饰符? |
| 5 | +atomic, nonatomic, readonly, readwrite, assign, strong, weak, copy, assign, retain, copy, setter=, getter= |
| 6 | + |
| 7 | +@property默认修饰符是atomic, readwrite, assign或strong |
| 8 | + |
| 9 | +###2. 什么情况使用 weak 关键字,相比 assign 有什么不同? |
| 10 | +什么情况使用 weak 关键字? |
| 11 | + |
| 12 | +1. 在 ARC 中,在有可能出现循环引用的时候,往往要通过让其中一端使用 weak 来解决,比如: delegate 代理属性或 NSTimer 属性 |
| 13 | + |
| 14 | +2. 自身已经对它进行一次强引用,没有必要再强引用一次,此时也会使用 weak ,自定义 IBOutlet 控件属性一般也使用 weak 。 |
| 15 | + |
| 16 | +不同点: |
| 17 | + |
| 18 | +1. weak 此特质表明该属性定义了一种“非拥有关系”(nonowningrelationship)。为这种属性设置新值时,设置方法既不保留新值,也不释放旧值。此特质同 assign 类似,然而在属性所指的对象遭到摧毁时,属性值也会清空(nil out)。 而 assign 的“设置方法”只会执行针对“纯量类型” (scalar type,例如 CGFloat 或 NSlnteger 等)的简单赋值操作。 |
| 19 | + |
| 20 | +2. assign 修饰非 OC 对象, weak 修饰 OC 对象。 |
| 21 | + |
| 22 | +###3. 怎么用 copy 关键字? |
| 23 | +属性NSString、NSArray、NSDictionary经常使用copy关键字,block 也经常使用 copy 关键字。 |
| 24 | + |
| 25 | +1. NSString、NSArray、NSDictionary使用copy关键字是为了防止给属性赋值的对象类型为NSMutableString、NSMutableArray、NSMutableDictionary,因为如果不使用copy,那么这些当可变类型的值被修改时,对应的NSString、NSArray、NSDictionary的值也会被修改。 |
| 26 | + |
| 27 | +2. block使用copy,是为了将block从栈空间移动到堆空间,从而使block可以保存block外传递进来的变量。 |
| 28 | + |
| 29 | +关于block做以下补充: |
| 30 | + |
| 31 | + |
| 32 | + |
| 33 | + |
| 34 | + |
| 35 | +###4. 这个写法会出什么问题:@property (copy) NSMutableArray*array; |
| 36 | +1. 无论赋值对象是什么类型,copy都会将其转化为一个不可变类型,即array的实际类型为NSArray,那么当array调用NSMutableArray的api时,就会导致崩溃。 |
| 37 | +```swift |
| 38 | +-[__NSArrayI removeObjectAtIndex:]: unrecognized selector sent to instance0x7fcd1bc30460 |
| 39 | +``` |
| 40 | +2. 如果按题目的写法,其默认关键字还有 atomic ,atomic不是线程安全的,无法保证array多读单写。因为 atomic 本身是在array的 set 和 get 方法中加了锁,但是当通过[array addObject:] 函数添加数据时,是不会调用 set 方法的,所以也就无法保证线程安全。另一方面同步锁因为在 set 和 get 方法中添加来锁,所以对性能会有一定的影响。所以在实际开发中,如果真的需要涉及到多读单写操作,我们也不会使用 atomic 来实现,而是在实际读写代码处,添加锁来实现。 |
| 41 | + |
| 42 | +###5. 如何让自己的类用 copy 修饰符?如何重写带 copy 关键字的 setter? |
| 43 | +如何让自己的类用 copy 修饰符 |
| 44 | +1. 需声明该类遵从 NSCopying 协议 |
| 45 | +2. 实现 NSCopying 协议。该协议只有一个方法: |
| 46 | +```swift - (id)copyWithZone:(NSZone *)zone;``` |
| 47 | + |
| 48 | +如何重写带 copy 关键字的 setter |
| 49 | +```swift |
| 50 | +-setValue(NSString* value){ |
| 51 | +if _value!= value{ |
| 52 | + _value= [value copy]; |
| 53 | + } |
| 54 | +} |
| 55 | +``` |
| 56 | + |
| 57 | +###6.@property 的本质是什么?ivar、getter、setter 是如何生成并添加到这个类中的 |
| 58 | +@property声明的属性,会在编译期生成对应的 getter、setter 方法,并会生成名称为_属性名称 的实例变量。 |
| 59 | + |
| 60 | +要注意的两点: |
| 61 | +1. 可以在类的实现代码里通过@synthesize 语法来指定实例变量的名字 |
| 62 | +2. 如果属性声明时带有@dynamic关键字,则告诉计算机不需要在编译期生成 getter、setter 方法。 |
| 63 | + |
| 64 | +###7.@protocol 和 category 中如何使用@property |
| 65 | + |
| 66 | +在协议和分类当中,都可以声明属性,但是我们先看看类对象(每个类只有一个类对象)的底层结构: |
| 67 | + |
| 68 | + |
| 69 | + |
| 70 | +分类的信息会在运行时阶段被动态的加入到类对象的 class_rw_t (readwrite)中,但是从 class_rw_t 的结构可以看出,并没有能够保存 实例变量 的容器,而对象的实例变量是在编译期生成并保存在 class_ro_t (readonly)当中的。所以得出结论如下: |
| 71 | + |
| 72 | +协议和分类中声明的属性,只会为属性生成对应的 getter、setter 方法,但是并不会生成实例变量。 |
| 73 | + |
| 74 | +我们可以使用运行时动态的给对象添加成员变量: |
| 75 | + |
| 76 | +```swift |
| 77 | +objc_setAssociatedObject |
| 78 | +objc_getAssociatedObject |
| 79 | +``` |
| 80 | +但这并不被推荐 |
| 81 | + |
| 82 | +###8. runtime 如何实现 weak 属性 |
| 83 | +首先,苹果为了内存优化,将 weak 弱引用保存在散列表(Hash表)中: |
| 84 | + |
| 85 | + |
| 86 | + |
| 87 | +一个对象,如果存在 weak 声明的属性,那么该属性就会被加入到一个数组中,而数组则会保存在这个散列表中。当这个对象被释放时,程序就会通过这个散列表,以对象为key,找到这个数组,并依次对其中的对象进行nil赋值操作。 |
| 88 | + |
| 89 | +###9. weak属性需要在dealloc中置nil么? |
| 90 | +不需要,理由请看8 |
| 91 | + |
| 92 | +###10.@synthesize和@dynamic分别有什么作用? |
| 93 | +@synthesize可以改变属性在编译器生成实例变量的名称。 |
| 94 | +@dynamic告知编译器不为属性生成对应的 getter、setter 方法。 |
| 95 | + |
| 96 | +###11. ARC下,不显式指定任何属性关键字时,默认的关键字都有哪些? |
| 97 | +@property默认修饰符是atomic, readwrite, assign或strong |
| 98 | + |
| 99 | +###12. 用@property声明的NSString(或NSArray,NSDictionary)经常使用copy关键字,为什么?如果改用strong关键字,可能造成什么问题? |
| 100 | +请查看问题3 |
| 101 | + |
| 102 | +###13.@synthesize合成实例变量的规则是什么?假如property名为foo,存在一个名为_foo的实例变量,那么还会自动合成新变量么? |
| 103 | +1. 如果指定了成员变量的名称,会生成一个指定的名称的成员变量。 |
| 104 | +2. 如果这个成员已经存在了就不再生成了。 |
| 105 | + |
| 106 | +所以存在一个名为_foo的实例变量,就不会再生成新变量了。 |
| 107 | + |
| 108 | +###14. objc中向一个nil对象发送消息将会发生什么? |
| 109 | +首先,需要搞明白2个问题: |
| 110 | +1. 什么是isa指针 |
| 111 | +2. 消息传递机制 |
| 112 | + |
| 113 | +isa指针是用于对象指向类对象,类对象指向元类对象的一个指针。而类对象和元类对象中又分别存放对象方法和类方法。 |
| 114 | +在消息传递机制中,就是通过isa指针来寻找到方法的实际调用地址的。 |
| 115 | + |
| 116 | +objc在向一个对象发送消息时,runtime库会根据对象的isa指针找到该对象实际所属的类,然后在该类中的方法列表以及其父类方法列表中寻找方法运行,然后在发送消息的时候,objc_msgSend方法不会返回值,所谓的返回内容都是具体调用时执行的。 那么,回到本题,如果向一个nil对象发送消息,首先在寻找对象的isa指针时就是0地址返回了,所以不会出现任何错误。 |
| 117 | + |
| 118 | +###15. objc中向一个对象发送消息[obj foo]和objc_msgSend()函数之间有什么关系? |
| 119 | +任何方法调用,都会在编译后转换为objc_msgSend()函数。该函数需要2个参数,一个是对象,一个是函数名称,即objc_msgSend(obj,@selector(foo))、 |
| 120 | + |
| 121 | +###16. 什么时候会报unrecognized selector的异常? |
| 122 | +当对象通过消息专递,动态方法解析,消息转发这一系列操作之后,发现这个方法任然无法被执行时,就会报该错。 |
| 123 | + |
| 124 | +什么是消息传递? |
| 125 | + |
| 126 | + |
| 127 | + |
| 128 | +什么是动态方法解析? |
| 129 | + |
| 130 | + |
| 131 | +什么是消息转发? |
| 132 | + |
| 133 | + |
| 134 | + |
| 135 | + |
| 136 | + |
| 137 | + |
| 138 | + |