zoukankan      html  css  js  c++  java
  • iOS 面试题、知识点 之一

    最近面试,发现这些题个人遇到的几率大一些,与大家分享一下,分三文给大家:

    当然Xcode新版本与之前一版本的区别,以及iOS新特性是必要了解的吧。

    Xcode8 和iOS 10 在之前文章有发过,感兴趣的可以查阅。 http://www.cnblogs.com/xujiahui/p/6025830.html

    之一:

    1.请简述你对协议的理解 官方定义协议:

    Protocols Define Messaging Contracts
    A class interface declares the methods and properties associated with that class. A protocol, by contrast, is used to declare methods and properties that are independent of any specific class.
    译:协议用来定义 消息契约 (暂且这么翻译) 一个类接口声明与类相关的方法和属性。一个协议,相比之 下,用于声明的方法和属性是独立于任何特定的类。

    总结一下: (1)协议相当于没有与类相关联的接口(网上也有说 协议是 一个方法签名的列表 ),他申明一组方法,列出他的参数 和返回值,共享给其他类使用,然后不进行实现,让用它的 类来实现这些方法 (2)在任何一个类中,只要声明了协议,都可以实现协议里 的方法。
    (3)协议不是一个类,且独立于任何特定的类。 (4)用@protocol 关键字声明一个协议
    委托:

    苹果的官方文档给了很清晰的解释:

    Delegation is a simple and powerful pattern in which one object in a program acts on behalf of, or in coordination with, another object. The delegating object keeps a reference to the other object—the delegate—and at the appropriate time sends a message to it. The message informs the delegate of an event that the delegating object is about to handle or has just handled. The delegate may respond to the message by updating the appearance or state of itself or other objects in the application, and in some cases it can return a value that affects how an impending event is handled. The main value of delegation is that it allows you to easily customize the behavior of several objects in one central object.

    意译一下就是:代理是一种简单而功能强大的设计模式,这 种模式用于一个对象“代表”另外 一个对象和程序中其他 的对象进行交互。 主对象(这里指的是 delegating object) 中维护一个代理(delegate)的引用并且在合适的时候向这 个代理发送消息。这个消息通知“代理”主对象即将处理或 是已经处理完了某一 个事件。这个代理可以通过更新自己 或是其它对象的 UI 界面或是其它状态来响应主对象所发送 过来的这个事件的消息。或是在某些情况下能返回一个值来

    影响其它 即将发生的事件该如何来处理。代理的主要价值 是它可以让你容易的定制各种对象的行为。注意这里的代理 是个名词,它本身是一个对象,这个对象是专门代表被代 理 对象来和程序中其他对象打交道的。

    委托是 objC 中使用非常频繁的一种设计模式,它的实现与 协议的使用是分不开的

    代理:
    在设计模式层面上:
    委托(delegate)也叫代理是 iOS 开发中常用的设计模式。 我们借助于 protocol 可以很方便的实现这种设计模式。

    2.如何理解 ARC 自动引用计数机制

    手动引用计数(Manully Reference Counting, aka MRC)

    Objective-C 的 MRC,简单来说就是一句话:谁创建,谁释 放。复杂一点的解释如下:

    • 所有由 alloc、copy(mutablecopy)、retain、new 创建 的 object,必须手动 release(或 autorelease)

    • 反之,则不需要也不可以

    • autorelease 不是自动释放,是 AutoreleasePool 的实 例,在 runloop 中被”稍后“释放。

    MRC 有什么问题 常犯的错误:

    • Crash! Reject! 内存管理是导致 app crash 的最主要 原因。也是 App Store 审核时拒审的最多的原因;

    • 规则简单,但细节太多,依赖于工程师的清醒头脑和良 好习惯,依赖于命名规范

    • Dangling Pointer,delegate 需要手动设置为 nil

    • 触发 NSError、或者有复杂的条件分支逻辑时,忘记释

      放内存 需要使用一堆工具,帮助你检测代码:

    • Instruments: Allocations, Leaks, Zombies

    • Static Analyzer

    • Heap

    • ObjectAlloc

    • vmmap

    • Debugger

      工程师需要做的事情:

    • 理解 MRC,写正确的代码

    • 正确的命名规范

    • 使用五花八门的辅助工具,来保证代码没问题

    • 保持清醒的头脑,不犯低级错误

      这不是工程师所擅长的事情,这个工作应该由编译器来做才 对—LLVM 3.1

      什么是 ARC

    • Objective-C 对象的自动管理机制

    • 由 LLVM 编译器来保证

    • 与 MRC 完全兼容

    • 引入新的运行时特性:弱指针、性能优化

      ARC 不是

    • 新的运行时模型

    • 自动 malloc/free, CF 等等(不负责纯 C 代码的内存管

      理)

    • 不是 GC。不扫描堆、不暂停进程运行、没有不确定的

      内存释放

    ARC 如何工作

    • 编译器在编译期,帮你动态添加 retain/release/autorelease

    • 返回同样结果的不同 API,在内存方面,没有区别(把 alloc/init 模式与 convenient method 当成一样就可 以了)

      ARC 有什么好处

    • 不用写 retain/release/autorelease 这样的代码,甚 至连 dealloc 方法都不需要(前提是类不需要管理 C 指 针)

    • 更好的性能,ARC 智能地在”适当“的地方插入 retain/release

    • Block just work

    • Less code, less bug

    • 少浪费脑细胞和脑时钟周期

      如何打开 ARC

    • Xcode 的 Project Setting 中,设置 Objective-C Automatic Reference Counting 为 YES

    • Xcode 4.2+,新的 Project 默认为 ARC

    为了实现 ARC,LLVM 编译器必须保证 4 条规则

    • 不能调用或实现跟引用计数相关的方法 (retain/release/autorelease/retaincount 等),否 则产生编译错误

    • C 的结构体里面,不能有 Object 指针;如果必须使用, 那么可以用 Objective-C 的类代替

    • 编译器必须清楚 void*是否被 retained。引入新的 API 来转换 Objective-C 和 Core Foundation 类型的对象

    • 编译器必须清楚自动释放的对象,因此 AutoreleasePool 不能是对象,而只是语义上的符号。 @autoreleasepool directive 甚至可能在 MRC 中使用

      如何理解 ARC

    • 从对象的从属关系角度考虑:强引用(retain)保证对象 的存在,或没有强引用,则对象被自动销毁

    • 想清楚程序的对象图

    • 不要再考虑 retain, release, autorelease 了

      弱引用(必须在 iOS 5 中使用)

      • 安全的”弱指针“,引用的对象被销毁时,自动变成 nil;避免了 Dangling Pointer

    • 在 property 中使用 weak 关键字声明,ivar 中使用_weak 声明

    循环引用

    • ARC 依然存在循环引用的可能

    • 手动设置某一个引用为 nil,破坏循环引用

    • 使用弱引用来避免

      性能

    • 与 MRC 没有实质的性能区别,甚至更好(有时候好得 多),内存峰值比 MRC 低

    • 没有 GC 的开销;没有延迟的销毁,没有进程暂停,没 有不能确定的释放

      ARC 的优点

    • 更容易理解

    • 写更少的代码,更少的 bug

    • 更容易维护,甚至更好的性能

    • 安全、稳定

    iOS 的什么版本才能支持 ARC

    • iOS 6 发布后,以 iOS 5.0 作为 Deployment Target 完 全没问题。所以都可以使用 ARC。如果你必须支持 5.0 以下的设备,那么看后两条。

    • ARC 由 LLVM 3.1 保证,LLVM 3.1 在安装 Xcode 4.2 自 动安装;也就是说只要 Xcode 4.2 以上的版本,可以设 置的 Deployment Target 的最低版本,都支持 ARC。笔 者在 4.0+的 app 中使用 ARC。

    • 弱引用(Weak Reference)必须在 iOS 5 以上的设备才 支持

      3. 如何理解

      retain/copy/assign/release/autorelease/deallo c 关键字

      首先了解: (1)内存管理

      范围:
      • 任何继承了 NSObject 的对象,对基本数据类型无效

      原理:

    • 每个对象内部都保存了一个与之相关联的整数,称为引 用计数器(auto reference count)

    • 每当使用 alloc、new 或者 copy 创建一个对象时,对 象的引用计数器被设置为 1

    • 给对象发送一条 retain 消息(即调用 retain 方法), 可以使引用计数器值+1

    • 给对象发送一条 release 消息,可以使引用计数器值-1

    • 当一个对象的引用计数器值为 0 时,那么它将被销毁,

      其占用的内存被系统回收,OC 也会自动向对象发送一 条 dealloc 消息。一般会重写 dealloc 方法,在这里释 放相关资源。一定不要直接调用 dealloc 方法。

    • 可以给对象发送 retainCount 消息获得当前的引用计 数器值。

      (2)内存管理原则

    1. 谁创建,谁释放(“谁污染,谁治理”)。如果你通过 alloc、new 或者(mutable)copy 来创建一个对象,那么 你必须调用 release 或 autorelease。或句话说,不是 你创建的,就不用你去释放

    2. 一般来说,除了 alloc、new 或 copy 之外的方法创建的 对象都被声明了 autorelease(autorelease 是延迟释

    放内存,不用你自己去手动释放,系统会知道在什么时

    候该去释放掉它。)
    3. 谁 retain,谁 release。只要你调用了 retain,无论

    这个对象是如何生成的,你都要调用 release

    retain:释放旧的对象,将旧对象的值赋给新对象,新对象 的引用计数加 1,属于指针拷贝。

    copy:建立一个索引计数为 1 的对象,然后释放旧对象,新对 象计数加 1,旧对象没有变化。

    assign: 简单赋值,不更改索引计数,对基础数据类型 (例 如 NSInteger,CGFloat)和 C 数据类型(int, float, double, char, 等) 适用简单数据类型。此标记说明设置器直接进 行赋值,这也是默认值。在使用垃圾收集的应用程序中,如 果你要一个属 性使用 assign,且这个类符合 NSCopying 协 议,你就要明确指出这个标记,而不是简单地使用默认值, 否则的话,你将得到一个编译警告。这再次向编译器说明你 确实需要赋值,即使它是 可拷贝的。

    release:引用计数减 1,nil 和 release 的区别:nil 就是把 一个对象的指针置为空,只是切断了指针与内存中对象的联

    系;而 release 才是真正通知内存释放这个对象。所以 nil 并没有释放内存,只有 release 才会真正释放内存。

    autorelease:自动释放对象,引用计数减 1

    原理:
    a.先建立一个 autorelease pool
    b.对象从这个 autorelease pool 里面生成。
    c.对象生成 之后调用 autorelease 函数,这个函数的作用 仅仅是在 autorelease pool 中做个标记,让 pool 记得将来 release 一下这个对象。
    d.程序结束时,pool 本身也需要 rerlease, 此时 pool 会把 每一个标记为 autorelease 的对象 release 一次。如果某个 对象此时 retain count 大于 1,这个对象还是没有被销毁。

    dealloc:对象的引用计数为 0 时调用,arc 里面的 dealloc 方法和 mrc 手动内存管理的区别在于:arc 里面不能调用 super 方法。arc 里面的 dealloc 一般用来注 NSNotification 或者 timer 之类的实例。如果是类里面的强引用,可以在 didReceiveMemoryWarning 置于 nil,如楼 上所说,确实 arc 的内存销毁有滞后性,但是从性能上来说 arc 更优.

    4.请简述 self.name = xxx 与_name= xxx 的区别

    前者会调用对象的 setName()方法,会使对象引用计数加 1,后者会直接把对象赋值给当前对象的 name 属性,引用 计数不增加。

    5. 请简述类别和继承有什么联系和区别 (1)继承

    这个是面向对象语言都有的一个特性,子类会继承父类的方 法和属性。 对于以下情况,无法使用类别,必须使用继承。 1)新扩展的方法与原方法同名,但是还需要使用父类的实 现。因为使用类别,会覆盖原类的实现,无法访问到原来的 方法。

    2)扩展类的属性,这个类别无法做到。

    (2)类别

    它是 OC 语言的一个特性,可以在不改变类名和原来类 的实现的前提下,实现对类的方法扩展。以下两种方式 最后使用类别。
    1)针对系统提供一些类,例如: NSString,NSArray,NSNumber 等类,系统本身不提倡 使用继承去扩展方法,因为这些类内部实现对继承有所 限制,所以最后使用类别来进行方法扩展。

    2)类别支持开发人员针对自己构建的类,把相关的方 法分组到多个单独的文件中,对于大型而复杂的类,这 有助于提高可维护性,并简化单个源文件的管理。

    6.请简述你对 strong 和 weak 关键字的理解

    iOS 5 中对属性的设置新增了 strong 和 weak 关键字来修饰 属性,实在 ARC 模式下。

    strong 用来修饰强引用的属性;

    @property (strong) SomeClass * aObject;
    对应原来的
    @property (retain) SomeClass * aObject; 和 @property (copy) SomeClass * aObject;
    weak 用来修饰弱引用的属性;
    @property (weak) SomeClass * aObject;
    对应原来的
    @property (assign) SomeClass * aObject;
    __weak, __strong 用来修饰变量,此外还有 __unsafe_unretained, __autoreleasing 都是用来修饰变 量的。
    __strong 是缺省的关键词。
    __weak 声明了一个可以自动 nil 化的弱引用。

    • • • •

    使用

    方法 法

    ARC 时,需要遵循一定的规则:
    不能使用 retain/release/retainCount/autorelease

    不能使用 NSAllocateObject/NSDeallocateObject 方

    不能显示的调用 dealloc 方法 使用@autoreleasepool 块代替 NSAutoreleasePool 不能使用 NSZone(防止内存碎片化而引入的结构) 显示转换"id"和"void *"

    __unsafe_unretained 声明一个弱应用,但是不会自动 nil 化,也就是说,如果所指向的内存区域被释放了,这个指针 就是一个野指针了。
    __autoreleasing 用来修饰一个函数的参数,这个参数会在 函数返回的时候被自动释放。

    7.请简述 weak 和 assgin 有什么区别

    (1)assign:对基础数据类型(NSInteger,CGFloat)和 C 数据类型(int, float, double, char 等),还有 id 类型

    (2)weak:ARC 模式下使用, 取代之前的 assign,对象销 毁之后会自动置为 nil,防止野指针。Assign 不能自动

    置为 nil,需要手动置为 nil。Delegate 基本总是使用 weak,以防止循环引用。特殊情况是,希望在 dealloc 中调用 delegate 的某些方法进行释放,此时如果使用 weak 将引起异常,因为此时已经是 nil 了,那么采用 assign 更为合适。

    8. 如何实现 ARC 和 MRC 的混合编程

    iOS5.0 以后就开始可以使用 ARC( Automatic Reference Counting:自动引用计数 )来代替之前的 MRC(Manual Reference Counting:人工引用计数)。使用 ARC 会减少很 多代码和忘了释放对象的苦恼。但是事情都有两面性。使用 了 ARC 之后如果你想复用以前写过的使用 MRC 的类, 就会 出报错。这时候怎么办?方法比较简单, 只需要做下面的 一个步骤就可以解决:

    在 targets 的 build phases 选项下 Compile Sources 下选 择要不使用 arc 编译的文件,双击它,输入 -fno-objc-arc 即可 MRC 工程中也可以使用 ARC 的类。方法如下:
    在 targets 的 build phases 选项下 Compile Sources 下选 择要使用 arc 编译的文件,双击它,输入 -fobjc-arc 即可

    9.Objective-c 中是否支持多继承

    OC 支持多继承,只要单继承,也就是说某个类只有一个 父类。当单继承不够用,很难为问题域建模时,我们通常都 会直接想到多继承。多继承是从多余一个直接基类派生类的 能力,可以更加直接地为应用程序建模。但是 Objective-C 不支持多继承,由于消息机制名字查找发生在运行时而非编 译时,很难解决多个基类可能导致的二义性问题。不过其实 Objective-C 也无需支持多继承,我们可以找到如下几种间 接实现多继承目的的方法:(1)消息转发 (2)delegate 和 protocol(3)类别

    10. Objective-c中变量默认是私有的吗,方法默认 是私有的吗
    OC – 类里面的方法只有两种, 静态方法和实例方法.

    在类里面声名一个私有方法 @interface MyClass : NSObject

    {
    NSString *something;

    }
    + (void)thisIsAStaticMethod;
    – (void)thisIsAnInstanceMethod;

    @end
    @interface MyClass

    (private)

    -(void)thisIsAPrivateMethod; @end

    @private 可以用来修饰私有变量
    在 Objective‐C 中,所有实例变量默认都是私有的,所有 实例方法默认都是公有的。

    11. #import"".h 和@class+类名的区别

    (1)import 会包含这个类的所有信息,包括实体变量和方法, 而@class 只告诉编译器,声明的类的名称,至于这些类是如 何定义的,暂时不用考虑,后面会再告诉你,所以在头文件 中如果用@class 声明某个类后,在.m 的实现中如果用到声 明类的具体方法或变量时还得再#import 类

    (2)在.h 头文件中进行声明时用#import 的话,如果 100 个 头文件都#import 同一个头件,或者这些文件是依次引用的, 如 A->B,B->C,C->D,当最开始的那个头文件有变化后进行 编译时,后面所有引用它的类都需要重新编译,如果引用最 开始的头文件 的类很多的话,那么这将耗费大量的时间,

    而用@class 则不会,可能有人会想即然.h 只是用@class 只 是简单的一个声明告编译器有这个类不让其报错,那么.m 中 要用到引入的类的方法和属性时,不还是要#import 头文件 一次,是的这个是对的,但编译器编译的时候只编译头文件 的,所以你的.m 中 用#import 与编译时间没太大关系

    (3)接下来说说什么时候该用@class,什么时候该用#import 进行声明,

    a.一般如果有继承关系的用#import,如B是A的子类那么 在B中声明A时用#import

    b.另外就是如果有循环依赖关系,如:A->B,B->A 这样相 互依赖时,如果在两个文件的头文件中用#import 分别声明 对方,那么就会出现头文件循环利用的错误,这时在头文件 中用@class 声明就不会出错

    c.还有就是自定义代理的时候,如果在头文件中想声明代理 的话如@interface SecondViewController:UIViewController<XXXDelegate> 时应用#import 不然的话会出错误,注意 XXXDelegate 是自 定义的.

    12. 请简述页面传值都有哪些实现方式

    属性/初始化/AppDelegate/单例/委托代理/消息 /block 这七种传值方法。

    13. 请简述深拷贝和浅拷贝的区别

    首先回顾下 copy 和 retain。copy 是创建一个新对象,retain 是创建一个指针,引用对象计数加 1。Copy 属性表示两个对 象内容相同,新的对象 retain 为 1 ,与旧有对象的引用计 数无关,旧有对象没有变化。copy 减少对象对上下文的依 赖。 retain 属性表示两个对象地址相同(建立一个指针, 指针拷贝),内容当然相同,这个对象的 retain 值+1 也就 是说,retain 是指针拷贝,copy 是内容拷贝。而我们说的 深和浅拷贝是针对指针地址来说的,地址相同,就是浅拷贝, 地址不同就是深拷贝。

    当然在 ios 中并不是所有的对象都支持 copy,mutableCopy, 遵守 NSCopying 协议的类可以发送 copy 消息,遵守 NSMutableCopying 协议的类才可以发送 mutableCopy 消息。 假如发送了一个没有遵守上诉两协议而发送 copy 或者 mutableCopy,那么就会发生异常。但是默认的 ios 类并没有 遵守这两个协议。如果想自定义一下 copy 那么就必须遵守

    NSCopying,并且实现 copyWithZone: 方法,如果想自定义 一下 mutableCopy 那么就必须遵守 NSMutableCopying,并且 实现 mutableCopyWithZone: 方法。

    14. 系统中有哪些对象是单例

    单例的应用十分普遍, 单例模式使一个类只有一个实 例 。使用单例好处:易于供外界访问;方便控制实例个数 , 节约系统资源 .

    (1)OC 中的 常见单例 : UIApplication /UIActionSheet/NSNotificationCenter/NSUserDefaults/ NSFIleManager。

    (2)应用程序中用到的单例: 背景音乐/音效管理等。 

  • 相关阅读:
    PL/SQL 中查询CLOB字段内容
    ubuntu14.04 swap not avalible交换分区不能使用
    ubuntu14.04安装ia32-lib
    rtems资料分享
    NIR相机
    rsync详解
    SublimeText3使用技巧总结
    msm8610 lcd driver code analysis
    Qualcomm Android display架构分析
    LCD framebuffer驱动设计文档
  • 原文地址:https://www.cnblogs.com/xujiahui/p/6042302.html
Copyright © 2011-2022 走看看