面试-年初面试问题精选

PS: 文章是从垃圾箱找出来的,之前误删了,看有些问题还是挺好的,所以再次发布出来。


Block在哪个内存区?

block块的存储位置(block入口的地址)可能存放在3个地方

  • 全局区
    • 不引用栈区的变量(如局部变量)和堆区的变量(如用alloc创建的对象)时,此时block存放在代码区
  • 堆区
    • 访问了堆区的变量,此时block存在于堆区
  • 栈区(MRC)

    • 访问了栈区的变量,此时block存在于栈区,在ARC情况下自动拷贝到堆区

    注:ARC情况下会自动拷贝到堆区、因此ARC下只有两个地方:全局区和堆区


如何实现深拷贝?
  • 1、基本数据类型直接可以实现深拷贝
  • 2、自定义数据类型需要实现NSCoping协议,并调用 copyWithZone:这个方法

手写冒泡排序算法
OC语言
NSMutableArray *nums = @[@2,@34,@8,@23,@5,@54,@333,@9].mutableCopy;

        for (int i = 0; i < nums.count; i++) {
            for (int j = 0; j < nums.count - i - 1; j++) {
                if (nums[j] > nums[j+1]) {
                    NSNumber *temp = nums[j];
                    nums[j] = nums[j+1];
                    nums[j+1] = temp;
                }
            }
        }    
NSLog(@"%@",nums);
// 打印结果
(
    2,
    5,
    8,
    9,
    23,
    34,
    54,
    333
)
C 语言
int nums[7] = {10,8,5,27,6,22,90};

    for (int i = 0; i < 7; i++) {
        for (int j = 0; j < 7 - i - 1; j++) {
            if (nums[j] > nums[j+1]) {
                int temp = nums[j];
                nums[j] = nums[j+1];
                nums[j+1] = temp;
            }
        }
    }

    for (int i = 0; i < 7; i++) {
        printf("%d  ",nums[i]);
    }

MVC 和 MVVM 区别及各自的优缺点?
MVC:

作为老牌架构, 优点在于将业务场景按展示数据类型划分出多个模块, 每个模块中的C层负责业务逻辑和业务展示, 而M和V应该是互相隔离的以做重用, 另外每个模块处理得当也可以作为重用单元. 拆分在于解耦, 顺便做了减负, 隔离在于重用, 提升开发效率. 缺点是没有区分业务逻辑和业务展示, 对单元测试不友好.


MVVM:

作为集大成者, 通过数据绑定做数据更新, 减少了大量的代码工作, 同时优化了代码逻辑, 只是学习成本有点高, 对新手不够友好.

MVVM 优点:
  • 1、由于展示逻辑被抽取到了 ViewModel 中,所以 View 中的代码将会变得非常轻量级;
  • 2、由于 ViewModel 中的代码是与 UI 无关的,所以它具有良好的可测试性;
  • 3、对于一个封装了大量业务逻辑的 Model 来说,改变它可能会比较困难,并且存在一定的风险。在这种场景下,ViewModel 可以作为 Model 的适配器使用,从而避免对 Model 进行较大的改动。

MVVM+RAC 结合使用实现双向绑定

通过KVO和RAC的RACSignal实现双向绑定

详见个人博客:

iOS-ReactiveCocoa(RAC)的高级使用之视图与模型的双向绑定


单利的几种实现方式
1、自己创建
+(instancetype)sharedSingleton 
{
    static id instance = nil;
    @synchronized (self) {
        if (!instance) {
            instance = [[self alloc] init];
        }
    }
    return instance;
}
2、通过GCD的dispatch_once创建(推荐)
+(instancetype)sharedSingleton
{
    static id instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[self alloc] init];
    });
    return instance;
}

Swift 与 Objective-c的区别
  • 1、强语言,更加严谨,每写一行代码系统都会自动检测是否有错误,这样就减少了运行后出错的可能;
  • 2、代码简洁,文件减少,语法简洁已读
  • 3、有命名空间
  • 4、性能更好,可以理解为没有C的OC,舍去了C,编译过程比OC少了一层
  • 5、没有了宏定义,摒弃了OC大量使用宏的弊端
  • 6、……自行补充吧,很多细节有变化,比如:懒加载,单例

Swift 中的@objc的作用
  • 在 Swift 代码中,使用@objc修饰后的类型,可以直接供 Objective-C 调用
  • Swift 为了效率禁用了 Objective-C 中有的动态特性,通过 @objc 关键字来使用动态特性

一个视图,旋转45度,frame和bounds如何变化?

frame会发生改变,而且变大,bounds不变

这里写图片描述

子视图旋转45度后:
这里写图片描述


WKWebView与H5交互,遇到的问题(项目中印象深的一个问题之一)?

用WKWebView与H5交互的时候,交互不成功,alert( )方法不被调用!不管是通过原声的交互方法,还是第三方,都不提示alert(),以为无法进行交互!最后发现WKWebView不支持JS的弹窗,需要自己实现对应方法,才可以显示alert弹窗。


KVO的底层实现?

Runtime
当你观察一个对象时,一个新的类会动态被创建。这个类继承自该对象的原本的类,并重写了被观察属性的 setter 方法。自然,重写的 setter 方法会负责在调用原 setter 方法之前和之后,通知所有观察对象值的更改。最后把这个对象的 isa 指针 ( isa 指针告诉 Runtime 系统这个对象的类是什么 ) 指向这个新创建的子类,对象就神奇的变成了新创建的子类的实例。


出现crash的情况有哪些?项目中遇到的哪些crash?

数组越界、野指针、数组插入空对象、拷贝自定义对象、类型不匹配、方法找不到……


一个类,实现了多个分类,实现了父类的同一个方法,执行顺序?

方法只会执行一次,谁第一个实现的分类,执行谁的分类方法实现


同一个线程,发出通知,自己的类中有一个观察者,其他类也有观察者,他们的执行顺序?

谁先注册,谁先执行


SDWebImage内部实现过程
  • 1、先把placeholderImage显示,然后 SDWebImageManager 根据 URL 开始处理图片;
  • 2、SDWebImageManager 从缓存查找图片是否已经下载;

    • 先从内存图片缓存查找是否有图片,如果内存中已经有图片缓存,前端展示图片
    • 如果内存缓存中没有,根据 URLKey 在硬盘缓存目录下尝试读取图片文件
  • 3、如果从硬盘缓存目录读取不到图片,说明所有缓存都不存在该图片,需要下载图片;

  • 4、下载完成,回调给需要的地方展示图片;
  • 5、将图片保存到 SDImageCache 中,内存缓存和硬盘缓存同时保存。

属性中的 copy 和 strong
  • 在平时定义属性的时候,对于NSString 和 block 我们经常用 copy 来修饰
  • 数组和字典等类型用 strong 来修饰;
  • 当使用 copy 修饰属性的时候,属性的setter方法会调用[object copy]产生新的对象,
  • 这样,当原object对象的值发生改变时,并不影响新对象值;
// 定义NSString
 @property(nonatomic, copy) NSString *name;

// 当调用上面的copy的时候,等价于下面的代码
- (void)setName:(NSString *)name {
      if (_name != name) {
         [_name release];
          _name = [name copy];
       }
}

当使用 strong 修饰属性的时候,属性的setter方法会直接强引用该对象,
这样,当原object对象的值发生改变时,新对象的属性也改变;

例如:我们平时使用strong修饰的NSMutableArray,这个可变数组在当前文件中只有一个,而且是可变的;

/** 数组 */
 @property(nonatomic,strong)NSMutableArray  *array;
 `
 `
 `
  // 当调用上面的strong的时候,等价于下面的代码
 -(void)setArray:(NSMutableArray *)array{    
      _array = array; 
  }

GCD的具体运用
  • 同步/异步 + 串行/并发队列的组合
  • 延迟执行(dispatch_after)
  • 只执行一次(dispatch_once)
  • 快速遍历(dispatch_apply)
  • 创建线程群组
    开启多条线程,去执行群组中的任务,当群组内的三个任务执行完毕后,再去执行notify里面的任务
    • 创建屏障线程队列
      会优先执行屏障前面的任务,当屏障前的所有任务执行完毕后,再去执行后面的任务
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
java面试题真的很多,下面我来回答一个有关多线程的问题。 在Java中实现多线程有两种方式,一种是继承Thread类,另一种是实现Runnable接口。这两种方式有何区别? 继承Thread类的方式是直接定义一个类继承Thread,并重写它的run()方法。然后创建该类的对象,并调用对象的start()方法来启动线程。这种方式简单直接,但因为Java是单继承的,所以如果某个类已经继承了其他类,就不能再直接继承Thread类实现多线程。 实现Runnable接口的方式是定义一个类实现Runnable接口,并实现其唯一的抽象方法run()。然后创建Thread类的对象,将实现了Runnable的对象作为参数传递给Thread类的构造方法。最后调用Thread对象的start()方法来启动线程。这种方式灵活性更大,因为Java允许一个类实现多个接口,所以即使某个类已经继承了其他类,仍然可以通过实现Runnable接口来实现多线程。 另一个区别在于资源共享的问题。继承Thread类的方式,不管是数据还是方法,都是线程自己拥有的,不存在共享的情况。而实现Runnable接口的方式,多个线程可以共享同一个对象的数据和方法,因为多个线程共同操作的是同一个Runnable对象。 总结来说,继承Thread类方式简单直接,但只能通过单继承来实现多线程;实现Runnable接口方式更灵活,可以解决单继承的限制,并且多个线程可以共享同一个Runnable对象的数据和方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值