MENU

iOS面试题练习(二)

February 27, 2017 • Read: 510 • iOS

前言

接上篇iOS面试题练习(一)继续

问题

@property 中有哪些属性关键字?

  • 内存管理语意
关键字解释
weak“非拥有关系”,为这种属性设置新值时,既不保留新值,也不释放旧值。当对象销毁时,自动置为nil。
strong对对象的一种拥有关系。先保留新值,释放旧值,然后再将新值设置上。
copy与strong类似。但是设置方法并不是保留新值,而是对其拷贝。
assign设置方法只会针对纯量类型的简单赋值操作。
unsafe_unretained和assign相当,适用于对象类型,表达一种非拥有关系,当目标对象遭到摧毁时,不会自动置为nil。
  • 原子性
关键字解释
atomic原子操作,编译器会通过锁定机制来确保其原子性。会消耗资源。
nonatomic非原子操作,大部分使用此特质
  • 读写权限
关键字解释
readwrite可读可写
readonly只读
  • 方法名
关键字解释
getter = < name >重新设置getter方法的名字
setter = < name >重新设置setter方法的名字,不常用

weak属性需要在dealloc中置nil么?

  • 不需要,前文提到过。对象销毁的时候,weak修饰的属性会自动置为nil。

@synthesize和@dynamic分别有什么作用?

  1. @property有两个对应的词,一个是 @synthesize,一个是 @dynamic。如果 @synthesize 和 @dynamic都没写,那么默认的就是@syntheszie var = _var;
  2. @synthesize 的语义是如果你没有手动实现 setter 方法和 getter 方法,那么编译器会自动为你加上这两个方法。
  3. @dynamic 告诉编译器:属性的 setter 与 getter 方法由用户自己实现,不自动生成。(当然对于 readonly 的属性只需提供 getter 即可)。假如一个属性被声明为 @dynamic var,然后你没有提供 @setter方法和 @getter 方法,编译的时候没问题,但是当程序运行到 instance.var = someVar,由于缺 setter 方法会导致程序崩溃;或者当运行到 someVar = var 时,由于缺 getter 方法同样会导致崩溃。编译时没问题,运行时才执行相应的方法,这就是所谓的动态绑定。

ARC下,不显式指定任何属性关键字时,默认的关键字都有哪些?

  1. 基本数据类型默认关键字是:

    • atomic,readwrite,assign
  2. 对应普通的OC对象

    • atomic,readwrite,strong

用@property声明的NSString(或NSArray,NSDictionary)经常使用copy关键字,为什么?如果改用strong关键字,可能造成什么问题?

  1. 因为父类指针可以指向子类对象,使用copy的目的就是为了让本对象的属性不受外界影响,使用copy无论传入的是一个可变对象还是一个不可变对象,本身持有的就是一个不可变的副本。
  2. 如果使用的是strong,那么这个对象就可能指向一个可变对象,如果外界改变了这个对象,那么就会影响该属性。

@synthesize合成实例变量的规则是什么?假如property名为foo,存在一个名为_foo的实例变量,那么还会自动合成新变量么?

  1. 如果指定了成员变量的名称,会生成一个指定名称的成员变量;
  2. 如果这个成员已经存在,就不在生成;
  3. 如果是@synthesize foo; 还会生成一个名称为foo的成员变量,也就是说:如果没有指定成员变量的名称,会自动生成一个属性同名的成员变量
  4. 如果是@synthesize foo = _foo; 就不会生成成员变量了。
    加入property名为foo,存在一个_foo的实例变量,就不会自动合成新变量了。

在有了自动合成属性实例变量之后,@synthesize还有哪些使用场景?

要回答这个问题,需要先理清楚什么情况不会使用autosynthesize(自动合成)。

  1. 同时重写了setter和getter方法
  2. 重写了只读属性的getter方法
  3. 使用了@dymic
  4. 在@protocol中定义的属性
  5. 在category中定义的所以属性
  6. 重载的属性

    • 当在子类中重载了父类的属性,就必须使用@synthesize来手动合成ivar。

在上面6中情况中,自动合成均不起作用,所以就需要用到@synthesize来手动合成ivar。同时,我们想指定实例变量的名字@synthesize firstName = _myFirstName,也可以使用@synthesize,但是不推荐这样用

objc中向一个nil对象发送消息将会发生什么?

  • 什么都不会发生,相当于一个空操作,返回nil(0)。Objective-C中的类的实例对象会有有个isa指针,指向其所属的类。但是实际上,类本身也是一个Object,类对象中也有一个isa指针,指向Meta Class,即元类。类对象是一个objc_class类型的结构体,其中包含了isa指针、父类、类名、类的版本信息、类信息、类的方法列表、类的成员列表等等信息。而向nil发送消息时,nil是OC中对象的空指针,在寻找isa指针的时候,就是0地址返回了,所以不会有任何错误。
  • 在OC中有nil,Nil,NULL,NSNull

    1. nil:指向OC中对象的空指针
    2. Nil:指向OC中类对象的空指针ßß
    3. NULL:指向其他类的空指针,如一个C类型的内存指针
    4. NSNull:在集合对象中,用来表示空值的对象。
      如果向NSNull类型的对象发送消息,就会抛出异常,而向nil则不会。

objc中向一个对象发送消息[obj foo]和objc_msgSend()函数之间有什么关系?

  • [obj foo]在编译后就成了objc_msgSend(obj,@selector(foo));
  • OC中的消息传递机制其实本质就是objc_msgSend()函数的调用。

什么时候会报unrecognized selector的异常?

  • 当调用对象上的某个方法,而该对象上没有实现这个方法的时候会报这个错。可以通过消息转发来解决
  • OC的运行时特性,方法在运行的时候会转换为消息发送。消息发送通过objc_msgSend()函数进行。先通过实例对象的isa指针找到类对象,类对象中包含了包括成员变量列表和方法列表等一系列的数据,而方法的执行就是要找类对象中方法列表的方法名称对应的方法实现。当在当前类对象中找不到的时候,就会去父类中找。如果父类中找不到,OC的运行时特性会给予3次补救机会,即消息转发。
  1. Method Resolution

    • 当类对象和父类中都没找到方法的时候,会首先进入+resolveInstanceMethod 或者 +resolveClassMethod方法,提供一个机会给你进行函数实现。如果添加了函数,那运行时系统会重启消息发送过程,放到你的函数实现中。否则,进入消息转发。
  2. Fast Forwarding

    • 如果没有实现Method Resolution则会进入此步。如果对象实现了-forwardingTargetForSelector:方法,Runtime会调用这个方法,给你提供一个把这个消息转发给其他对象的机会。只要这个方法返回的不是nil和self,整个消息发送过程就会重启。当然发送消息的对象也会从原对象变成你在函数中返回的对象。否则继续Normal Forwarding.这里叫做Fast是因为下面的方法会创建一个NSInvocation对象,所以相对快一点。
  3. Normal Forwarding

    • 这是Runtime提供的最后一个挽救机会。首先它会发送-methodSigntureForSelect:消息获得函数签名,也就是参数和返回值类型。
    • 在上面的函数返回不为空的情况,Runtime则会调用-forwardInvocation:消息给对象。如果没有函数签名,则Runtime会发出-doesNotRecognizeSelector:消息,程序也就崩溃了。

参考

《招聘一个靠谱的 iOS》—参考答案(上)

Archives QR Code
QR Code for this page
Tipping QR Code