总结一下最近面试遇到的一些问题吧

写在前面的话

最近在面试,和大部分iOS开发者一样,很明显感受到行情很差,总结起来原因不外乎如下几点:
1、iOS开发人员猛增,初中级太多,高级仍然稀缺;
2、移动互联网市场趋于稳定,需求降低;
3、iOS开发相对成熟,公司企业要求提高不少;

关于我

从事iOS开发3年,基本开发流程、基本技能和独立开发能力都没有问题,和大多数人一样,在平时开发过程中可能太过于依赖开源代码,导致对iOS高级部分可能理解尚浅。其中有几家面试影响特别深刻,问得非常细,他们要求是5年经验以上,我自认还达不到,所以心服口服。

被问到的一些问题
1、delegate和block的区别?

*我相信大多数开发者应该会这么答:
两者都是回调机制,block在写法上更加简洁,并且更注重结果(比如我只需要回调成功或者失败),而delegate更注重过程(比如我想要知道回到的成功、失败和进度以及结果的各种数据等)。
*其实它们还有更高阶的理解:
delegate是用weak修饰的,目的也就是为了防止循环引用和内存泄漏(假设A-B,B已经强引用A了,那么在A.delegate = B的时候,A又会强引用B,因此造成循环引用,造成的结果是两个对象都不能被释放,体现在不会执行dealloc,因此也就内存泄漏了),而block为什么要用copy修饰呢?这是因为block默认创建是存在栈中,可能随时会被释放,一旦外部调用就会crash,所有我们用copy先将block深拷贝到堆中,这样访问就可以正常访问,然而这样势必会造成循环引用,因此在调用的时候需要__weak CurrentViewController * blockSelf = self; (MAC中则将weak改成block),从而解决了block循环引用的问题。

2、id和instancetype的区别?

其实很简单,id是可以指向任何类型对象的关键字,而instanceType是指向本类同类型的关键字。虽然很简单,但你得知道。

3、谈谈多线程
更多更详细多线程知识

常见的三种:NSThread、GCD和NSOperation(NSOprationQueue)
NSThread:

// 创建
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:nil];
// 启动
[thread start];

// 创建并自动启动
[NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:nil];

//  另一种方法,不过苹果后面认为是不安全的
[self performSelectorInBackground:@selector(run:) withObject:nil];

GCD(grand central dispatch)

**队列**
// 主队列
dispatch_queue_t queue = ispatch_get_main_queue();
// 自定义队列--串行队列
  dispatch_queue_t queue = dispatch_queue_create("tk.bourne.testQueue", NULL);
  dispatch_queue_t queue = dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_SERIAL);
// 自定义队列--并行队列
  dispatch_queue_t queue = dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_CONCURRENT);
// 全局并行队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

**任务**
// 同步
dispatch_sync(<#queue#>, ^{
      //code here
  });
// 异步
dispatch_async(<#queue#>, ^{
      //code here
  });

**队列组**
//1.创建队列组
dispatch_group_t group = dispatch_group_create();
//2.创建队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

//3.多次使用队列组的方法执行任务, 只有异步方法
//3.1.执行3次循环
dispatch_group_async(group, queue, ^{
    for (NSInteger i = 0; i < 3; i++) {
        NSLog(@"group-01 - %@", [NSThread currentThread]);
    }
});

//3.2.主队列执行8次循环
dispatch_group_async(group, dispatch_get_main_queue(), ^{
    for (NSInteger i = 0; i < 8; i++) {
        NSLog(@"group-02 - %@", [NSThread currentThread]);
    }
});

//4.都完成后会自动通知
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    NSLog(@"完成 - %@", [NSThread currentThread]);
});

NSOperation和NSOperationQueue

NSOperation 是苹果公司对 GCD 的封装,完全面向对象,所以使用起来更好理解。 NSOperation 和 NSOperationQueue 分别对应 GCD 的 任务 和 队列 。NSOperation 只是一个抽象类,所以不能封装任务。但它有 2 个子类用于封装任务。分别是:NSInvocationOperation 和 NSBlockOperation 。创建一个 Operation 后,需要调用 start 方法来启动任务,它会 默认在当前队列同步执行。当然你也可以在中途取消一个任务,只需要调用其 cancel 方法即可。

**NSOperation**
//1.创建NSInvocationOperation对象
  NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];

//2.开始执行
  [operation start];

//1.创建NSBlockOperation对象
      NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
          NSLog(@"%@", [NSThread currentThread]);
      }];

      //添加多个Block
      for (NSInteger i = 0; i < 5; i++) {
          [operation addExecutionBlock:^{
              NSLog(@"第%ld次:%@", i, [NSThread currentThread]);
          }];
      }

      //2.开始任务
      [operation start];

 **NSOperationQueue**
 // 主队列
 NSOperationQueue *queue = [NSOperationQueue mainQueue];

// 其他队列
//1.创建一个其他队列    
NSOperationQueue *queue = [[NSOperationQueue alloc] init];

//2.创建NSBlockOperation对象
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"%@", [NSThread currentThread]);
}];

//3.添加多个Block
for (NSInteger i = 0; i < 5; i++) {
    [operation addExecutionBlock:^{
        NSLog(@"第%ld次:%@", i, [NSThread currentThread]);
    }];
}

//4.队列添加任务
[queue addOperation:operation];

// 特别说明:要实现串行队列的话,只需要在创建队列的时候设置如下
maxConcurrentOperationCount = 1// NSOperation 有一个非常实用的功能,那就是添加依赖。比如有 3 个任务:A: 从服务器上下载一张图片,B:给这张图片加个水印,C:把图片返回给服务器。这时就可以用到依赖了:
//1.任务一:下载图片
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"下载图片 - %@", [NSThread currentThread]);
    [NSThread sleepForTimeInterval:1.0];
}];

//2.任务二:打水印
NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"打水印   - %@", [NSThread currentThread]);
    [NSThread sleepForTimeInterval:1.0];
}];

//3.任务三:上传图片
NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"上传图片 - %@", [NSThread currentThread]);
    [NSThread sleepForTimeInterval:1.0];
}];

//4.设置依赖
[operation2 addDependency:operation1]; //任务二依赖任务一
[operation3 addDependency:operation2]; //任务三依赖任务二

//5.创建队列并加入任务
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperations:@[operation3, operation2, operation1] waitUntilFinished:NO];

动画效果

在iOS中如果使用普通的动画则可以使用UIKit提供的动画方式来实现,如果想实现更复杂的效果,则需要使用Core Animation了。
UIKit动画包括两类:
1、通过动画上下文使用UIKit动画
2、通过代码块使用UIKit动画
Core Animation包括三类:
1、自定义动画:CABasicAnimation
2、关键帧动画:CAKeyframeAnimation
3、使用路径制作动画:CATransitionAnimation

运行时runtime

runtime是什么?

runtime是一套底层的C语言API,包含很多强大实用的C语言数据类型和C语言函数,平时我们编写的OC代码,底层都是基于runtime实现的。OC中一切都被设计成了对象,我们都知道一个类被初始化成一个实例,这个实例是一个对象。实际上一个类本质上也是一个对象,在runtime中用结构体表示:

//类在runtime中的表示
struct objc_class {
    Class isa;//指针,顾名思义,表示是一个什么,
    //实例的isa指向类对象,类对象的isa指向元类

#if !__OBJC2__
    Class super_class;  //指向父类
    const char *name;  //类名
    long version;
    long info;
    long instance_size
    struct objc_ivar_list *ivars //成员变量列表
    struct objc_method_list **methodLists; //方法列表
    struct objc_cache *cache;//缓存
    //一种优化,调用过的方法存入缓存列表,下次调用先找缓存
    struct objc_protocol_list *protocols //协议列表
    #endif
} OBJC2_UNAVAILABLE;
/* Use `Class` instead of `struct objc_class *` */

runtime有什么用?

能动态产生、修改和删除一个类,一个成员变量,一个方法

runtime有哪些常用的方法?

class_copyIvarList()返回一个指向类的成员变量数组的指针
class_copyPropertyList()返回一个指向类的属性数组的指针
ivar_getName()获取成员变量名-->C类型的字符串
property_getName()获取属性名-->C类型的字符串
-------------------------------------
typedef struct objc_method *Method;
class_getInstanceMethod() 
class_getClassMethod()以上两个函数传入返回Method类型
---------------------------------------------------
method_exchangeImplementations()交换两个方法的实现

runtime在开发中有哪些用处?

1、获取一个类的全部属性
2、遍历类的属性,快速归档(json数据形成模型)
3、可防止数组或者字典传nil导致的程序崩溃

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值