搞定iOS面试【一】

简介

整理iOS相关知识点,为面试做准备。

instancetype比id类型更加安全

看一段官方给出的demo

@interface MyObject : NSObject
+ (instancetype)factoryMethodA;
+ (id)factoryMethodB;
@end

@implementation MyObject
+ (instancetype)factoryMethodA { return [[[self class] alloc] init]; }
+ (id)factoryMethodB { return [[[self class] alloc] init]; }
@end

void doSomething() {
    NSUInteger x, y;

    x = [[MyObject factoryMethodA] count]; // Return type of +factoryMethodA is taken to be "MyObject *"
    y = [[MyObject factoryMethodB] count]; // Return type of +factoryMethodB is "id"
}

x将会报警告,因为+factoryMethodA返回的是instance类型,该消息表达式的类型是MyObject *,但MyObject没有-count方法,编译器会给一条警告。
但factoryMethodB返回的是id类型,他可以是任何类,切调用的-count可能存在于某个类的某处,对于编译器来说,+factoryMethodB的返回值调用count方法是可以实现的,这可能造成无预警的崩溃。

copy属性的使用

copy属性一般用于以下对象的声明中

  1. NSString、NSArray、NSDictionary 等等经常使用copy关键字,是因为他们有对应的可变类型:NSMutableString、NSMutableArray、NSMutableDictionary;
  2. block代码块声明

注意 block 使用 copy 是从 MRC 遗留下来的“传统”,在 MRC 中,方法内部的 block 是在栈区的,使用 copy 可以把它放到堆区.在 ARC 中写不写都行:对于 block 使用 copy 还是 strong 效果是一样的,但写上 copy 也无伤大雅,还能时刻提醒我们:编译器自动对 block 进行了 copy 操作。建议多写代码做做实验,如下

@property (nonatomic, copy) NSString *userId;

- (instancetype)initWithUserId:(NSString *)userId {
   self = [super init];
   if (!self) {
       return nil;
   }
   _userId = [userId copy];
   return self;
}

为什么不能用copy属性声明NSMutableArray

添加,删除,修改数组内的元素的时候,程序会因为找不到对应的方法而崩溃.因为 copy 就是复制一个不可变 NSArray 的对象,例如下面的代码

@property (nonatomic, copy) NSMutableArray *mutableArray;

NSMutableArray *array = [NSMutableArray arrayWithObjects:@1,@2,nil];
self.mutableArray = array;
[self.mutableArray removeObjectAtIndex:0];

对数组进行增删改的时候就会崩溃。

atomic与nonatomic

在默认情况下,由编译器所合成的方法会通过锁定机制确保其原子性(atomicity)。如果属性具备 nonatomic 特质,则不使用同步锁。请注意,尽管没有名为“atomic”的特质(如果某属性不具备 nonatomic 特质,那它就是“原子的”(atomic))。

在iOS开发中,你会发现,几乎所有属性都声明为 nonatomic。

一般情况下并不要求属性必须是“原子的”,因为这并不能保证“线程安全” ( thread safety),若要实现“线程安全”的操作,还需采用更为深层的锁定机制才行。例如,一个线程在连续多次读取某属性值的过程中有别的线程在同时改写该值,那么即便将属性声明为 atomic,也还是会读到不同的属性值。

因此,开发iOS程序时一般都会使用 nonatomic 属性。但是在开发 Mac OS X 程序时,使用 atomic 属性通常都不会有性能瓶颈。

@protocol 和 category 中如何使用 @property

  1. 在 protocol 中使用 property 只会生成 setter 和 getter 方法声明,我们使用属性的目的,是希望遵守我协议的对象能实现该属性
  2. category 使用 @property 也是只会生成 setter 和 getter 方法的声明,如果我们真的需要给 category 增加属性的实现,需要借助于运行时的两个函数:

    a. objc_setAssociatedObject

    b. objc_getAssociatedObject

@property中有哪些属性关键字?/ @property后面可以有哪些修饰符?

  1. 原子性— nonatomic特质

    在默认情况下,由编译器合成的方法会通过锁定机制确保其原子性(atomicity)。如果属性具备非原子特性,则不使用自旋锁。请注意,尽管没有名为“atomic”的特质某属性不具备非原子特质,那它就是“原子的”(原子)),但是仍然可以在属性特质中写明这一点,编译器不会报错。特质相符的原子性。

  2. 读/写权限— readwrite(读写),readonly (只读)
  3. 内存管理语义— assign,strong,weak,unsafe_unretained,copy
  4. 方法名— getter=,setter=如:
   @property(nonatomic,getter = isOn)BOOL on;
  1. 不常用的:nonnull,null_resettable,nullable

一个objc对象的isa的指针指向什么?有什么作用

指向他的类对象,从而可以找到对象上的方法.

objc中的类方法和实例方法有什么本质区别和联系?

类方法

  1. 类方法是属于类对象的
  2. 类方法只能通过类对象调用
  3. 类方法中的self是类对象
  4. 类方法可以调用其他类方法
  5. 类方法中不能访问成员变量
  6. 类方法中不能直接调用成员变量

实例方法

  1. 实例方法是属于实例对象的
  2. 实例方法只能通过实例对象调用
  3. 实例方法中的self是实例对象
  4. 实例方法中可以访问成员变量
  5. 实例方法中直接调用实例方法
  6. 实例方法中也可以调用类方法(通过类名)
本文总阅读量