美文网首页
iOS面试题-开发实用篇

iOS面试题-开发实用篇

作者: 洁简 | 来源:发表于2018-03-16 18:45 被阅读47次

    简述APP生命周期

    一张图即可反映APP生命周期:

    APP
    APP启动过程及简单优化
    1. 解析Info.plist
    加载相关信息,如闪屏
    沙箱建立,权限检查
    2. Mach-O加载
    如果是胖二进制,寻找合适CUP类别的部分
    加载所有依赖Mach-O文件
    定位内部,外部指针引用,如字符串,函数
    执行声明函数
    加载扩展类
    C++静态对象加载,调用Objc的+(load)函数
    3. 程序执行
    main函数
    执行UIApplicationMain函数
    UIApplicationDelegate对象开始处理监听事件
    
    如果APP启动缓慢,可以想到的因素
    main() 函数内有耗时操作;
    动态库加载太多;
    rootViewControlle以及childViewController的加载,view和subViews的加载耗时;
    优化:
    移除不需要用到的动态库
    移除不需要用到的类
    合并功能类似的类和扩展(Category)
    压缩图片资源
    优化applicationWillFinishLaunching
    优化rootViewController加载
    

    UIViewController 的生命周期

    0.loadView:加载视图
    1.loadViewIfNeeded(iOS9后):重新加载视图包括viewDidLoad
    2.viewDidLoad:视图控制器中的视图加载完成,viewController自带的view加载完成
    3.viewWillAppear:视图将要出现
    4.viewWillLayoutSubviews:即将布局其 Subviews
    5.viewDidLayoutSubviews:已经布局其 Subviews
    6.viewDidAppear:视图已经出现
    7.viewWillDisappear:视图将要消失
    8.viewDidDisappear:视图已经消失
    这个面试点在实际开发中还是比较重要的,毕竟写个视图都会有自己的生命周期,从而更好的优化视图加载.
    

    一张老图:

    生命周期
    loadView什么作用
    loadView在View为nil时调用,早于ViewDidLoad,通常用于代码实现控件,收到内存警告时会再次调用。
    loadView默认做的事情是:如果此Viewcontroller存在一个对应的nib文件,那么就加载这个nib。否则,就创建一个UIView对象。
    如果你用Interface Builder来创建界面,那么不应该重载这个方法。
    
    如果你想自己创建View对象,那么可以重载这个方法,此时你需要自己给View属性赋值。
    你自定义的方法不应该调用super。如果你需要对View做一些其他定制操作,在ViewDidload中去做
    
    根据上面说明可以知道,有两种情况:
    
    1、如果你用了nib文件,重载这个方法就没有太大意义。因为loadView的作用就是加载nib。
    如果你重载了这个方法不调用super,那么nib文件就不会被加载。
    如果调用了super,那么view已经加载完了,你需要做的其他事情在viewDidLoad里面做更合适。
    
    2、如果你没有用nib,这个方法默认就是创建一个空的view对象。如果你想自己控制view对象的创建,
    例如创建一个特殊尺寸的view,那么可以重载这个方法,自己创建一个UIView对象,然后指定 self.view = myView;
    但这种情况也没有必要调用super,因为反正你也不需要在super方法里面创建的view对象。如果调用了super,那么就是浪费了一些资源而已
    

    View中的加载顺序

    1.initWithCoder(如果没有storyboard就会调用initWithFrame)
    2.awakeFromNib:作为第一个方法的助手,方便处理一些额外的设置。
    3.layoutSubviews:一般设置子控件的frame。
    4.drawRect:UI控件都是画上去的,在这一步就是把所有的东西画上去。
    layoutSubviews方便数据计算,drawRect方便视图重绘。
    drawRect在以下情况下会被调用:
    1、如果在UIView初始化时没有设置rect大小,将直接导致drawRect不被自动调用。drawRect 掉用是在Controller->loadView,Controller->viewDidLoad两方法之后掉用的.
      所以不用担心在 控制器中,这些View的drawRect就开始画了.这样可以在控制器中设置一些值给View(如果这些View?draw的时候需要用到某些变量 值).
    2、该方法在调用sizeToFit后被调用,所以可以先调用sizeToFit计算出size。然后系统自动调用drawRect:方法。
    3、通过设置contentMode属性值为UIViewContentModeRedraw。那么将在每次设置或更改frame的时候自动调用drawRect:。
    4、直接调用setNeedsDisplay,或者setNeedsDisplayInRect:触发drawRect:,但是有个前提条件是rect不能为0。
    在实际开发中layoutSubviews个人用的比较多,用来重新设置控件大小.
    drawRect一般用来做绘图个人用的不多.
    

    什么是KVC和KVO?

    KVC也就是key-value-coding,即键值编码,通常是用来给某一个对象的属性进行赋值.
    开发中我们可以对私有属性进行赋值的,修改一些控件的内部属性,还可以用于字典转模型.
    KVO,即key-value-observing,利用一个key来找到某个属性并监听其值得改变。其实这也是一种典型的观察者模式。
    大致用法:
    1.添加观察者
    2.在观察者中实现监听方法,observeValueForKeyPath: ofObject: change: context:
    3.移除观察者
    简单实现原理:
    当一个类的属性被观察的时候,系统会通过runtime动态的创建一个该类的派生类,并且会在这个类中重写基类被观察的属性的setter方法,
    而且系统将这个类的isa指针指向了派生类,从而实现了给监听的属性赋值时调用的是派生类的setter方法。
    重写的setter方法会在调用原setter方法前后,通知观察对象值得改变。
    KVC/KVO实现的根本是Objective-C的动态性和runtime
    

    开发中,保存数据有哪几种方式?

    所谓的持久化,就是将数据保存到磁盘中,使得在应用程序重启后可以继续访问之前保存的数据.
    iOS本地数据保存有多种方式,比如NSUserDefaults、Plist文件保存、归档(NSKeyedArchiver)、SQLite、CoreData、KeyChain(钥匙串)等多种方式。
    NSUserDefaults:
      NSUserDefaults 是一个单例对象,在整个应用程序的生命周期中都只有一个实例。
      NSUserDefaults保存的数据类型有:NSNumber, 基本数据类型(int,NSInter,float,double,CGFlat......),   NSString, NSData, NSArray, NSDictionary, NSURL。
      NSUserDefaults一般保存配置信息,比如用户名、密码、是否保存用户名和密码、是否离线下载等一些配置条件信息。
    plist文件保存:
      plist文件是将某些特定的类,通过XML文件的方式保存在目录中。
      plist主要保存的数据类型为NSString、NSNumber、NSData、NSArray、NSDictionary。
    可以看出NSUserDefaults和plist有一定局限性.
    归档:在iOS中是另一种形式的序列化,只要遵循了NSCoding协议的对象都可以通过它实现序列化。
      需要注意的:必须遵循并实现NSCoding协议;保存文件的扩展名可以任意指定;继承时必须先调用父类的归档解档方法
    上面的几个存储方法,都是覆盖存储。如果想要增加一条数据就必须把整个文件读出来,然后修改数据后再把整个内容覆盖写入文件。所以它们都不适合存储大量的内容。
    因此保存大量数据可以优先考虑用数据库,sql语句对查询操作有优化作用,所以从查询速度或者插入效率都是很高的。
    SQLite:在iOS中要使用SQLite3,需要添加库文件:libsqlite3.dylib并导入主头文件,这是一个C语言的库,所以直接使用SQLite3还是比较麻烦的。
      不过在一般开发过程中,使用的都是第三方开源库 FMDB,封装了这些基本的c语言方法,使得我们在使用时更加容易理解,提高开发效率。
    CoreData:
      CoreData框架提供了对象-关系映射(ORM)的功能,即能够将OC对象转化成数据,保存在SQLite3数据库文件中,也能将保存在数据库中的数据还原成OC对象.在次数据操作期间,不需要编写任何SQL语句.
    上面几种都是保存到沙盒中.
    KeyChain:钥匙串是苹果公司Mac OS中的密码管理系统。一个钥匙串可以包含多种类型的数据:密码(包括网站,FTP服务器,SSH帐户,网络共享,无线网络,加密磁盘镜像等),私钥,电子证书和加密笔记等。
      当应用程序被删除后,保存到KeyChain里面的数据不会被删除,所以KeyChain是保存到沙盒范围以外的地方。安全性也比较高.
      KeyChain还有一个用途,就是替代UDID。UDID已经被废除了,所以只能用UUID代替,所以我们可以把UUID用KeyChain保存。
    

    关键字const/static/extern、UIKIT_EXTERN区别和用法以及与宏的区别

    const:
      1.const用来修饰右边的基本变量或指针变量
      2.被修饰的变量只读,不能被修改
      int  const  *p   //  *p只读 ;p变量
      int  *const  p  // *p变量 ; p只读
      const  int   *const p //p和*p都只读
      int  const  *const  p   //p和*p都只读
      开发者经常定义只读变量:
      const CGFloat kWidth = 10.0;
    static:
      1.修饰局部变量,保证局部变量永远只初始化一次,在程序的运行过程中永远只有一份内存,  生命周期类似全局变量了,但是作用域不变。
      2.修饰全局变量使全局变量的作用域仅限于当前文件内部,即当前文件内部才能访问该全局变量。
      3.修饰函数时,被修饰的函数被称为静态函数,使得外部文件无法访问这个函数,仅本文件可以访问
       另外在开发中经常在单例中使用.
    extern:它的作用是声明外部全局变量。这里需要特别注意extern只能声明,不能用于实现,而且定义和分配内存都在原来类中。
      UIKIT_EXTERN:可以解决重复定义的问题,可以参照苹果的做法,比如系统预置的通知:
      UIKIT_EXTERN NSString *const   UIKeyboardWillShowNotification;
      UIKIT_EXTERN NSString *const  UIKeyboardDidShowNotification;
    宏:1.宏在编译开始之前就会被替换,而const只是变量进行修饰; 
      2.宏可以定义一些函数方法,const不能 
      3.宏编译时只替换不做检查不报错,也就是说有重复定义问题。而const会编译检查,会报错  
    定义不对外公开的常量的时候,我们应该尽量先考虑使用 static 方式声名const来替代使用宏定义。const不能满足的情况再考虑使用宏定义。
    例如:
      static const CGFloat kWidth = 10.0;
      可以代替 #define WIDTH 10.0
    

    block的实质是什么?一共有几种block?都是什么情况下生成的?

    block对象是一个c语言级别的语法和运行机制。它与标准c函数类似,不同之处在于,它除了有可执行的代码之外,还包含了与堆、栈内存绑定的变量。
    作为一个回调,block特别的有用,因为block既包含了回调期间的代码,又包含了执行期间需要的数据。
    iOS中有三种:
    NSStackBlock    存储于栈区
    NSGlobalBlock   存储于程序数据区
    NSMallocBlock   存储于堆区
    NSGlobalBlock:
      block 内部没有引用外部变量的 Block 类型都是 NSGlobalBlock 类型,存储于全局数据区,由系统管理其内存,retain、copy、release操作都无效。
    NSStackBlock:
      block 内部引用外部变量,retain、release 操作无效,存储于栈区,变量作用域结束时,其被系统自动释放销毁.但在ARC下block 变量在赋值的时候系统自动将其拷贝到堆区了
    NSMallocBlock:
      [block retain],[blockA copy]操作后变量类型变为 NSMallocBlock,支持retain、release.
    

    代理、通知、block和单例使用场景

    代理:这是很常用的方式,特点是一对一的形式,而且逻辑结构非常清晰。需要定义协议方法并且实现协议方法,会使代码结构变复杂.
    通知:通知中心实际上是在程序内部提供了消息广播的一种机制。通知中心是基于观察者模式的,它允许注册、删除观察者。它是多对多关系.
    block:是一段特殊的代码块。使用起来有点像函数.特点也是一对一的,代码结构更加紧凑,不需要额外定义方法.
    这几个在开发中经常用于数据传递,如果只是单个参数往往使用block,如果参数内容较多则使用代理传值.而如果是跨界面传值往往使用通知传值.
    当然传值的方式还有单例,数据存储来做传值.
    

    frame和bounds有什么不同?

    frame指的是:该view在父view坐标系统中的位置和大小。(参照点是父亲的坐标系统)
    bounds指的是:该view在本身坐标系统中 的位置和大小。(参照点是本身坐标系统)
    理解这两个概念在实际开发中还是比较重要的.
    

    UIView、CALayer和UIWindow是什么关系?

    UIView是iOS系统中界面元素的基础, 所有的界面元素都继承自它, UIView本身完全是由CoreAnimation来实现. 真正的绘图部分, 是由一个CALayer类来管理.
    最大的区别是UIView继承自UIResponder, 能接收并响应事件, 负责显示内容的管理, 
    而CALayer继承自NSObject, 不能响应事件, 负责显示内容的绘制.UIView是基于CALayer的高层封装。而CALayer不支持自动布局.
    另外UIWindow是一种特殊的UIView,通常在一个程序中只会有一个UIWindow,但可以手动创建多个UIWindow,同时加到程序里面。UIWindow在程序中主要起到三个作用:
    1、作为容器,包含app所要显示的所有视图
    2、传递触摸消息到程序中view和其他对象
    3、与UIViewController协同工作,方便完成设备方向旋转的支持
    

    isMemberOfClass 、 isKindOfClass和 isSubclassOfClass 联系与区别

    联系:都能检测一个对象是否是某个类的成员
    区别:
    isKindOfClass:确定一个对象是否是一个类的成员,或者是派生自该类的成员.
    isSubclassOfClass和isKindOfClass的作用基本上是一致的,只不过一个是类方法,一个是对象方法。
    isMemberOfClass:确定一个对象是否是当前类的成员.他的筛选条件更为苛刻,只有当类型完全匹配的时候才会返回YES。
    

    将一个函数在主线程执行的几种方法

    //GCD方法,通过向主线程队列发送一个block块,使block里的方法可以在主线程中执行。
    dispatch_async(dispatch_get_main_queue(), ^{
        //需要执行的方法
    });
    //NSOperation 方法
    NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        //需要执行的方法
    }];
    [mainQueue addOperation:operation];
    //NSThread 方法
    [self performSelector:@selector(method) onThread:[NSThread mainThread] withObject:nil waitUntilDone:YES modes:nil];
    [self performSelectorOnMainThread:@selector(method) withObject:nil waitUntilDone:YES];
    [[NSThread mainThread] performSelector:@selector(method) withObject:nil];
    //RunLoop方法
    [[NSRunLoop mainRunLoop] performSelector:@selector(method) withObject:nil];
    

    相关文章

      网友评论

          本文标题:iOS面试题-开发实用篇

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