iOS面试笔试题(2018年8月)

作者: 爱恨的潮汐 | 来源:发表于2018-08-21 13:25 被阅读57次
    一、第一家面试题
    IMG_6615.jpg IMG_6616.jpg IMG_6617.jpg
    二、第二家面试题
    IMG_6632.jpg IMG_6631.jpg
    三、答案
    1.1、当使用 weak修饰的对象被释放后,系统是否直接释放掉此对象?其实现原理是什么? (15分)

    答案:weak指针不会增加所引用对象的计数,并在引用对象被回收的时候自动被置为nil。

    实现原理:runtime 对注册的类, 会进行布局,对于 weak 对象会放入一个 hash 表中。 用 weak 指向的对象内存地址作为 key,当此对象的引用计数为0的时候会 dealloc,假如 weak 指向的对象内存地址是a,那么就会以a为键, 在这个 weak 表中搜索,找到所有以a为键的 weak 对象,从而设置为 nil。

    1.2、声明可变数组可以用weak修饰吗?和用strong修饰有什么区别? (10 分)

    答案:数组怎么能用weak啊,如果用weak,那么数组一创建完毕就被销毁了。只能用strong。强引用,不会被释放。

    1.3、反转二叉树。(10 分)
    /**
     *  翻转二叉树(又叫:二叉树的镜像)
     *
     *  @param rootNode 根节点
     *
     *  @return 翻转后的树根节点(其实就是原二叉树的根节点)
     */
    + (BinaryTreeNode *)invertBinaryTree:(BinaryTreeNode *)rootNode {
        if (!rootNode) {
            return nil;
        }
        if (!rootNode.leftNode && !rootNode.rightNode) {
            return rootNode;
        }
        
        [self invertBinaryTree:rootNode.leftNode];
        [self invertBinaryTree:rootNode.rightNode];
        
        BinaryTreeNode *tempNode = rootNode.leftNode;
        rootNode.leftNode = rootNode.rightNode;
        rootNode.rightNode = tempNode;
        
        return rootNode;
    }
    

    参考:https://www.cnblogs.com/menchao/p/5266286.html

    1.4、ViewControllerA push到ViewControllerB,再从B pop回A的生命周期.(15分)
    #pragma mark --- life circle
    
    // 非storyBoard(xib或非xib)都走这个方法
    - (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
        NSLog(@"%s", __FUNCTION__);
        if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
        
        }
        return self;
    }
    
    // 如果连接了串联图storyBoard 走这个方法
    - (instancetype)initWithCoder:(NSCoder *)aDecoder {
         NSLog(@"%s", __FUNCTION__);
        if (self = [super initWithCoder:aDecoder]) {
            
        }
        return self;
    }
    
    // xib 加载 完成
    - (void)awakeFromNib {
        [super awakeFromNib];
         NSLog(@"%s", __FUNCTION__);
    }
    
    // 加载视图(默认从nib)
    - (void)loadView {
        NSLog(@"%s", __FUNCTION__);
        self.view = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
        self.view.backgroundColor = [UIColor redColor];
    }
    
    //视图控制器中的视图加载完成,viewController自带的view加载完成
    - (void)viewDidLoad {
        NSLog(@"%s", __FUNCTION__);
        [super viewDidLoad];
    }
    
    
    //视图将要出现
    - (void)viewWillAppear:(BOOL)animated {
        NSLog(@"%s", __FUNCTION__);
        [super viewWillAppear:animated];
    }
    
    // view 即将布局其 Subviews
    - (void)viewWillLayoutSubviews {
        NSLog(@"%s", __FUNCTION__);
        [super viewWillLayoutSubviews];
    }
    
    // view 已经布局其 Subviews
    - (void)viewDidLayoutSubviews {
        NSLog(@"%s", __FUNCTION__);
        [super viewDidLayoutSubviews];
    }
    
    //视图已经出现
    - (void)viewDidAppear:(BOOL)animated {
        NSLog(@"%s", __FUNCTION__);
        [super viewDidAppear:animated];
    }
    
    //视图将要消失
    - (void)viewWillDisappear:(BOOL)animated {
        NSLog(@"%s", __FUNCTION__);
        [super viewWillDisappear:animated];
    }
    
    //视图已经消失
    - (void)viewDidDisappear:(BOOL)animated {
        NSLog(@"%s", __FUNCTION__);
        [super viewDidDisappear:animated];
    }
    
    //出现内存警告  //模拟内存警告:点击模拟器->hardware-> Simulate Memory Warning
    - (void)didReceiveMemoryWarning {
        NSLog(@"%s", __FUNCTION__);
        [super didReceiveMemoryWarning];
    }
    
    // 视图被销毁
    - (void)dealloc {
        NSLog(@"%s", __FUNCTION__);
    }
    
    1.5、UIView和CALayer有什么关系? (10 分)

    1.首先UIView可以响应事件,Layer不可以.
    2.View和CALayer的Frame映射及View如何创建CALayer.
    一个 Layer 的 frame 是由它的 anchorPoint,position,bounds,和 transform 共同决定的,而一个 View 的 frame 只是简单的返回 Layer的 frame,同样 View 的 center和 bounds 也是返回 Layer 的一些属性。
    3.UIView主要是对显示内容的管理而 CALayer 主要侧重显示内容的绘制。

    总结
    (1)UIView负责处理用户交互,负责绘制内容的则是它持有的那个CALayer,我们访问和设置UIView的这些负责显示的属性实际上访问和设置的都是这个CALayer对应的属性,UIView只是将这些操作封装起来了而已。

    (2)CALayer作为一个跨平台框架(OS X和iOS)QuatzCore的类,负责MAC和iPhone(ipad等设备)上绘制所有的显示内容。而iOS系统为了处理用户交互事件(触屏操作)用UIView封装了一次CALayer,UIView本身负责处理交互事件,其持有一个Layer,用来负责绘制这个View的内容。而我们对UIView的和绘制相关的属性赋值和访问的时候(frame、backgroundColor等)UIView实际上是直接调用其Layer对应的属性(frame对应frame,center对应position等)的getter和setter。

    1.6. 下面代码的输出是什么?(10分)
    @implementation Son : Father
    -(id)init {
        if (self= [super init]) {
              NSLog(@"%@", NSStringFromClass([self class]));
              NSLog(@"%@", NSStringFromClass([super class]));
                  return self;
           }
    @end
    

    答案:两个都打印出:Son。
    self 是类的隐藏参数,指向当前调用方法的这个类的实例。
    super是一个Magic Keyword,它本质是一个编译器标示符,和self是指向的同一个消息接收者。

    不同的是:super会告诉编译器,调用class这个方法时,要去父类的方法,而不是本类里的。
    上面的例子不管调用[self class]还是[super class],接受消息的对象都是当前 Son *obj 这个对象。

    1.7、在项目中,若出现以下的代码可能会有什么问题?(10分)
     for(int i=0;i< 1000;i++) {
            NSString *num = [NSString stringWithFormat:@"%d",i];//num是临时变量
        }
    

    答案:大次数循环内存暴涨问题。
    该循环内产生大量的临时对象,直至循环结束才释放,可能导致内存泄漏,解决方法为在循环中创建自己的autoReleasePool,及时释放占用内存大的临时变量,减少内存占用峰值。

    1.8、内存泄漏可能会出现的几种原因,聊聊你的看法?如果是非OC对象如何处理?若常用框架出现内存泄漏如何处理?(20分)

    答案:https://www.jianshu.com/p/0f6119115548

    2.1、frame和bounds 有什么不同?

    答案:frame指的是:该view在父view坐标系统中的位置和大小。(参照点是父亲的坐标系统)bounds指的是:该view在本身坐标系统中的位置和大小。(参照点是本身坐标系统)bounds指的是以自己为原点的坐标系。父视图bouns改变,子视图会移动。

    2.2、0bjective-C 的类可以多重继承么?可以实现多个接口么? Category 是什么?重写一个类的方式用继承好还是分类好?为什么?

    答案:Objective-c只支持单继承,如果要实现多继承的话,可以通过类别和协议的方式来实现,cocoa中所有的类都是NSObject 的子类,多继承在这里是用protocol委托代理来实现的。
    Category是类别,一般用分类比较好,用Category去重写类的方法,仅对本Category有效,不会影响到其他类与原有类的关系

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

    答案:用@property声明 NSString、NSArray、NSDictionary 经常使用copy关键字,是因为他们有对应的可变类型:NSMutableString、NSMutableArray、NSMutableDictionary,他们之间可能进行赋值操作,为确保对象中的字符串值不会无意间变动,应该在设置新属性值时拷贝一份。

    2.4、Category (类别)、Extension (扩展)和继承的区别?

    答案:类扩展 Extension 可以为类添加属性和方法。
    类别 Category 只能添加方法不能添加属性,添加属性调用的时候会 Crash,因为并不会为类 Category 的属性生成 Get 和 Set 方法。

    2.5、什么时候用delete, 什么时候用Notification?

    答案:delegate(委托模式):1对1的反向消息通知功能。
    Notification(通知模式):只想要把消息发送出去,告知某些状态的变化。但是并不关心谁想要知道这个。

    2.7、如何访问并修改一个类的私有属性?

    答案:方式一:通过KVC访问并修改。
    方式二:通过runtime访问并修改。获取对象属性列表。

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

    答案:指向他的类对象,从而可以找到对象上的方法。

    答案二:
    isa 指的就是 是个什么,对象的isa指向类,类的isa指向元类(meta class),元类isa指向元类的根类。isa帮助一个对象找到它的方法。
    isa:是一个Class 类型的指针. 每个实例对象有个isa的指针,他指向对象的类,而Class里也有个isa的指针, 指向meteClass(元类)。元类保存了类方法的列表。当类方法被调用时,先会从本身查找类方法的实现,如果没有,元类会向他父类查找该方法。同时注意的是:元类(meteClass)也是类,它也是对象。元类也有isa指针,它的isa指针最终指向的是一个根元类(root meteClass).根元类的isa指针指向本身,这样形成了一个封闭的内循环。

    2.9、isKindOfClass、isMemberOfClass、 selector 作用分别是什么?

    答案:isKindOfClass:作用是某个对象属于某个类型或者继承自某类型。
    isMemberOfClass:某个对象确切属于某个类型。
    selector:通过方法名,获取在内存中的函数的入口地址。

    2.10、lldb (gdb)常用的控制台调试命令?

    答案:
    1). p 输出基本类型。是打印命令,需要指定类型。是print的简写

    p (int)[[[self view] subviews] count]

    2). po 打印对象,会调用对象description方法。是print-object的简写

    po [self view]

    3). expr 可以在调试时动态执行指定表达式,并将结果打印出来。常用于在调试过程中修改变量的值。

    4). bt:打印调用堆栈,是thread backtrace的简写,加all可打印所有thread的堆栈

    5). br l:是breakpoint list的简写

    2.11、_objc msgForward 函数是做什么的,直接调用它将会发生什么?

    答案:_objc_msgForward是IMP类型,用于消息转发的:当向一个对象发送一条消息,但它并没有实现的时候,_objc_msgForward会尝试做消息转发
    直接调用_objc_msgForward是非常危险
    的事,这是把双刃刀,如果用不好会直接导致程序Crash,但是如果用得好,能做很多非常酷的事。

    2.12、 什么是TCP / UDP?

    答案:
    (1)TCP的全称为传输控制协议。这种协议可以提供面向连接的、可靠的、点到点的通信。,是面向连接的,建立连接需要经历三次握手,保证数据正确性和数据顺序。
    TCP传输数据的形式:点对点传输数据 传输过程比较复杂 但是比较安全 不会出现丢包的现象(比如:QQ文件传输)

    (2)UDP全称为用户数据报协议,它可以提供非连接的不可靠的点到多点的通信。是非连接的协议
    UDP传输数据的形式:点对面传输数据 传输过程非常简单 但是比较不安全 经常出现丢包的现象 传输方只管传输不管接收方是否接受成功(比如:短信群发)
    IP 由46位(0255之间的数字组成) 作为设备的唯一标识

    (3)TCP 的三次握手
    第一次握手:客户端发送 syn 包到服务器,并进入 syn_send状态,等待服务器进行确认;
    第二次握手:服务器收到客户端的 syn 包,必须确认客户的SYN,同时自己也发送一个 SYN 包,即 SYN + ACK 包,此时服务器进入 SYN_RECV 状态;
    第三次握手:客户收到服务器发送的 SYN+ACK 包之后,向服务器发送确认包, 此包发送完毕,客户端和服务器进入ESTABLISHED 状态,完成第三次握手。

    2.13、用伪代码写一个线程安全的单例模式。
    static id _instance;
    + (id)allocWithZone:(struct _NSZone *)zone {
       static dispatch_once_t onceToken;
       dispatch_once(&onceToken, ^{
           _instance = [super allocWithZone:zone];
       });
       return _instance;
    }
    
    + (instancetype)sharedData {
       static dispatch_once_t onceToken;
       dispatch_once(&onceToken, ^{
           _instance = [[self alloc] init];
       });
       return _instance;
    }
    
    - (id)copyWithZone:(NSZone *)zone {
       return _instance;
    }
    
    
    2.14、HTTP协议中POST方法和GET方法有那些区别?

    答案:GET用于向服务器请求数据,POST用于提交数据
    GET请求,请求参数拼接形式暴露在地址栏,而POST请求参数则放在请求体里面,因此GET请求不适合用于验证密码等操作
    GET请求的URL有长度限制(最多255byte),POST请求不会有长度限制

    2.15、如何高性能的给 UIImageView 加个圆角?
    (1)不好的解决方案:

    使用下面的方式会强制Core Animation提前渲染屏幕的离屏绘制, 而离屏绘制就会给性能带来负面影响,会有卡顿的现象出现。
    self.view.layer.cornerRadius = 5.0f;
    self.view.layer.masksToBounds = YES;

    (2)正确的解决方案:使用绘图技术
    - (UIImage *)circleImage {
        // NO代表透明
        UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0);
        // 获得上下文
        CGContextRef ctx = UIGraphicsGetCurrentContext();
        // 添加一个圆
        CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height);
        CGContextAddEllipseInRect(ctx, rect);
        // 裁剪
        CGContextClip(ctx);
        // 将图片画上去
        [self drawInRect:rect];
        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
        // 关闭上下文
        UIGraphicsEndImageContext();
        return image;
    }
    
    (3)还有一种方案:

    使用了贝塞尔曲线"切割"个这个图片, 给UIImageView 添加了的圆角,其实也是通过绘图技术来实现的。

    UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
    imageView.center = CGPointMake(200, 300);
    UIImage *anotherImage = [UIImage imageNamed:@"image"];
    UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, NO, 1.0);
    [[UIBezierPath bezierPathWithRoundedRect:imageView.bounds
                           cornerRadius:50] addClip];
    [anotherImage drawInRect:imageView.bounds];
    imageView.image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    [self.view addSubview:imageView];
    

    相关文章

      网友评论

      • WhatMotto:哪家公司
      • 我是C:这套面试题还可以,好多面试题回答都是错误的
        爱恨的潮汐:@我是C 额,这里面有错误么,欢迎指出:smile:
      • 不知蜕变的挣扎:mark
        常义:1.4 生命周期那个题是ViewController出现到消失的生命周期吧他问的好像不是这吧?:smile:

      本文标题:iOS面试笔试题(2018年8月)

      本文链接:https://www.haomeiwen.com/subject/eondiftx.html