美文网首页
objective-c 复习

objective-c 复习

作者: iChuck | 来源:发表于2018-03-13 16:22 被阅读14次
  1. 方法和选择器有和不同(difference between method and selector?)

    • selector 是一个方法的名字。method 是一个实体,包含了名字和实现。
  2. Core Foundation 的内存管理

    • 凡是带有 create、copy、retain 等字眼的函数,创建出来的对象,都要在最后做一次 release
    • 比如 CFRunLoopObserverCreate release 函数:CFRelease(对象);
  3. malloc 和 new 的区别

    • new 是 C++ 中的操作符,malloc 是 c 中的一个函数
    • new 不止是分配内存,而且会调用类的构造函数,同理 delete 会调用类的析构函数,而 malloc 则只分配内存,不会进行初始化类成员的工作,同样 free 也不会调用析构函数
    • 内存泄漏对于 malloc 或者 new 都可以检查出来的,区别在于 new 可以指明是哪个文件的哪一行,而 malloc 没有这些信息
    • new 和 malloc 的效率比较
    • new 可以认为是 malloc 加构造函数的执行
    • new 出来的指针是直接带类型信息的
  4. OC 中的反射机制

- class 反射
1. 通过类名的字符串形式实例化对象
Class class = NSClassFromString(@"student");
Student *stu = [[class alloc] init];
2. 将类名转换成字符串
Class class = [Student class];
NSString *className = NSStringFromClass(class);

- SEL 反射
1. 通过方法的字符串形式实例化方法
SEL selector = NSSelectorFromClass(@"setName");
[stu performSelector:selector withObject:@:Mike"];
2. 将方法转换成字符串
NSStringFromSelector(@selector(setName:));
  1. 什么是 SEL?如何声明一个 SEL?通过哪些方法能够调用 SEL 包装起来的方法?

    • SEL 就是对方法的一种包装。包装的 SEL 类型数据它对应相应的方法地址,找到方法地址就可以调用方法。在内存中每个类的方法都存储在类对象中,每个方法都有一个与之对应的 SEL 类型的数据,根据一个 SEL 数据就可以找到对应的方法的地址,进而调用方法。
    • SEL s1 = @selector(test1); // 将 test1方法包装成 SEL 对象
    • SEL s2 = NSSelectorFromString(@"test1"); // 将一个字符串方法转换成为 SEL 对
    • 调用方式 :[person text] 或者 SEL aa = @selector(text);[person performSelector:aa];
  2. 协议中<NSObject>是什么意思?子类继承父类,那么子类会遵守父类中遵守的协议吗?协议中能够定义成员变量吗?如何约束一个对象类型的变量要存储的地址是遵从一个协议对象?

    • 遵守 NSObject 协议
    • 能,但是只能在头文件中声明,编译器是不会自动生成实例变量的。需要自己处理 getter 和 setter 方法
    • id <NSObject>
  3. 面向对象有哪些特征以及你对这些特征的理解

    • 继承:继承是从已有类获得继承信息创建新类的过程。提过继承信息的类被称为父类(超类、基类);得到继承信息的被称为子类(派生类)。继承让变化中的软件系统有了一定的延续性,同事继承也是封装过程中可变因素的重要手段。
    • 封装:封装是把数据和操作数据的方法绑定起来,对数据的访问只能通过已定义的接口。我们在类中编写的方法就是对实现细节的一种封装;我们编写一个类就是对数据和数据操作的封装。可以说,封装就是隐藏一切可隐藏的东西,只向外界提供最简单的编程接口。
    • 多态性:多态性是指允许不同子类型的对象对同一消息做出不同的响应。简单的说就是用同样的对象引用调用同样的方法但是做了不同的事情。多态性分为编译时的多态性和运行时的多态性。方法重载(overload)实现的编译时的多态性(也称为前绑定),而方法重写(override)实现的运行时的多态性(也称后绑定)。运行时的多态是面向对象最精髓的东西,要实现多态需要两件事:1.方法重写(子类继承父类并重写父类中已有的或抽象方法);2.对象造型(用父类型引用子类型对象,这样同样调用引用调用同样的方法就会根据子类对象的不同而表现出不同的行为)
    • 抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两个方面。抽象只关注对象有哪些属性和行为,并不关注这些行为的细节是什么。
  4. 我们说oc 是动态运行时语言是什么意思?(When we call Obecjtiove-c is runtime language what does it mean?)

    • 主要是将数据类型的确定由编译时,推迟到运行时。这个问题其实前涉及到两个概念,运行时和多态。
    • 简单的说,运行时机制使我们直到运行时才去决定一个对象的类别,以及调用该类别对象指定方法。
    • 多态:不同对象以自己的方式响应相同的消息的能力叫做多态。
    • 意思就是假设生物类(life)都拥有一个相同的方法-eat;那人类属于生物,动物也属于生物,都继承了 life 后,实现各自的 eat,但是调用是我们只需要调用各自的 eat 方法。也就是不同的对象对自己的方式响应了相同的消息(响应了 eat 这个选择器)。因此可以说,运行时机制就是多态的基础。
  5. oc 中属性的作用

    • readwrite 是可读可写特性;需要生成 getter 方法和 setter 方法
    • readonly 是只读特性 只会生成 getter 方法不会生成 setter 方法,不希望属性在类外改变
    • assign 是赋值特性,setter 方法将传入参数赋值给实例变量;仅设置变量时;assign用于简单的数据类型
    • retain 表示持有性 setter 方法将传入的参数先保留一份,再赋值,传入参数的引用计数 retaincount会+1
    • copy 表示赋值特性,setter 方法将出入的对象复制一份;需要完全一份新的变量时
    • nonatomic 非原子操作,决定编译器生成 getter setter 是否是源自操作
    • atomic 表示多线程安全(性能低)
  6. 简述 Notification、KVC、KVO、delegate?并说明他们之间的区别?

    • KVO(key-value-observing):一对多,观察折模式,键值观察机制,它提供了观察某一属性的变化方法,极大简化了代码
    • KVC(key-value-Coding)是键值编码,一个对象在调用 setValue 的时候:检查是否存在响应 key 的 set 方法,存在就调用 set 方法;set 方法不存在,就查找_key 的成员变量是否存在,存在就直接赋值;如果_key 没找到就查找相同名称的key,存在就赋值;如果没有就调用 valueForUndefinedKey 和 setValue:forUndefinedKey
    • Delegate:通过发送者和接受者的关系一对一的关系。代理的目的是改变或者传递控制链。允许一个类在某些特定的时刻通知到其他类,而不需要获取那些类的指针。可以减少框架复杂度。消息的发送者(sender)告知接收者(receiver)某个事件将要发生,delegate 同意然后发送者响应事件,delegate 机制使得接收者可以改变发送者的行为。
    • Notification:观察者模式,通常发送者和接受者的关系是间接的多对多关系。消息的发送者告知接收者事件已经发生或者将要发送,仅此而已,接收者并不能反过来影响发送者的行为。
    • 区别:delegate 效率比 Notification 高,代理更加直接,需要关注返回值,所以代理方法往往包含 should 很传神的词。相反的,通知最大的特色是不关心结果。所以通知往往用 did 这个词汇。 两个模块不是很紧密就可以用通知,例如多线程之间的传值。页面间的传递就用delegate 可以更好的实现数据的交互。
  7. 懒加载(what is lazy loading)

    • 只有用到的时候才去初始化。也可以理解成为延迟加载。
    • 我觉得最好也见得的例子就是 tableview 中图片的加载显示了,一个延迟加载,避免内存过高,一个异步加载,避免线程阻塞提高用户体验。
  8. OC 有多继承吗?没有的话可以用什么方法代替?

    • oc 没有多继承。(多继承即一个子类可以有多个父类,继承了多个父类的特性)
    • 可以通过协议和类别实现。
    • protocol 可以实现多个接口,通过实现多个接口可以完成多继承。
    • category 一般使用分类,用 category 去重写类的方法,仅对 category 有效,不会影响到其他类与原生类的关系。
  9. 类别category 和延展 extensions 是什么?以及两者的区别?继承和类别在实现中有什么区别?为什么 category 只能为对象添加方法,却不能添加成员变量呢?

    • 类别:在没有原类.m 文件的基础上,给该类添加方法。
    • 延展:一种特殊形式的类别,主要在一个类的.m 文件里声明和实现延展的作用,就是给某类添加私有方法或者私有变量。
    • 两者的区别:延展可以添加属性并且它添加的方法必须要实现的。延展可以认为一个私有的类目。类别可以在不知道,不改变源代码的情况下往里面添加方法,只能添加,不能删除和修改。并且如果类别和原来类中的方法重名,则类别将覆盖原来的方法,因为类别有更高的优先级。继承可以修改添加删除方法,添加属性。
    • category 只能为对象添加方法,却不能添加成员变量,原因如果可以添加成员变量,添加成员变量没有办法初始化。
  10. oc 有私有方法吗?如果没有的话用什么代替方法?

    • 没有。只有静态方法和实例方法两种。但是可以通过声明和定义都放在.m 文件来实现一个表面上私有方法。有私有变量,可以通过@private 来修饰,或者把声明放到.m 文件中。在 oc 中,所有实例变量默认都是私有的,所有实例方法都是公有的。
  11. include 与#import 的区别?#import 和@class 的区别?

    • import 指令是 oc 针对#include 的进行改版,#import 确保引用的文件只被引用一次,这样你就不会陷入递归包含中。
    • import 会链入头文件的所有信息,包括实例变量和方法等;而@class 只是告诉编译器,其后面声明的名称是类的名称,至于这些类是如何定义的,暂时不用考虑。在头文件中一般使用@class 来声明这个名称是类的名称,不需要知道其内部的实现实体变量和方法。而实现类里面,因为会用到这个引用类的内部的实体变量和方法,所以需要使用#import 来包含这个被引用类的头文件。在编译效率方面,如果你有100个头文件都#import 了同一个文件,或者这些文件都是以此引用的如 A->B->C->D 这样的引用关系,当最开始的那个头文件有变化的话,后面所有引用它的类都需要重新编译,如果你的类有很多的话,这将耗费大量的时间。而@class 不会。如果循环相互依赖#import 会报错,而@class 不会(A->B, B->A)
  12. 浅复制和深复制的区别?

    • 浅复制(copy):只复制指向对象的指针,而不复制引用对象本身。
    • 深复制(mutableCopy):复制引用对象本身。深复制就好理解了,内存中存在了两份独立对象本身,当修改 A 是,A_Copy 不变。
  13. oc、c、c++之间的联系和区别?

    • oc 和 c++都是 c 的面向对象超集
    • oc 是完全动态的,支持在运行时动态类型决议( dynamic typing)、动态绑定(dynamic binding)以及动态加载(dynamic loading);而 c++ 是部分动态的,编译时静态绑定,通过嵌入类(多重继承)和虚函数(虚表)来模拟实现的。
    • oc 在语言层次上支持动态消息转发,其消息发送语法为[object function];而 c++为 object->function().两者的语义也不同,在 oc 里是说发送消息到一个对象上,至于这个对象能不能响应消息以及是响应还是转发消息都不会 crash;而在 c++里是说对象进行了某个操作,如果对象没有操作的话,要么编译失败,要么程序 crash 掉的(动态绑定)
  14. 目标-动作机制

    • 目标是动作消息的接收者,一个控件或者更为常见的其它单元,以插座变量的形式保有其动作消息的目标。
    • 动作是控件发送给目标的消息,或者从目标的角度看,它是目标为了响应动作而实现的方法,程序需要某些机制来进行事件和指令的翻译。这个机制就是目标-动作机制。
  15. oc 的优缺点

    • 优点:Category、Posing、动态识别、指标计算、弹性信息传递、不是一个过度复杂的 c 衍生语言、oc 可以和 c++混合编程
    • 缺点:不支持命名空间、 不支持运算符重载、不支持多继承、使用动态运行时类型,所有方法都是函数调用,所以很多编译时优化方法都用不到。(如内联函数等),性能低劣。
  16. C 语言的函数调用和 oc 的消息机制有什么区别?

    • 对于 c 语言,函数的调用在编译的时候就会决定调用哪个函数,编译完成之后直接顺序执行。
    • oc 的函数调用成为消息发送。属于动态调用过程。在编译的时候并不能决定真正调用哪个函数(事实证明,在编译阶段,oc 可以调用任何函数,即使这个函数并未实现,只要申明过就不会报错。而 c 语言在编译阶段就会报错)。只有在真正运行的时候才会根据函数的名称找到对应的函数来调用。
  1. C 与 OC 混用

    • 处理.m 可以识别c 和 oc,.mm 可以识别 c、c++、oc 但是cpp 只能用 c/c++
  2. 常见的 oc 数据类型哪些?和 c 有基本类型有什么区别

    • 常见的:NSInteger(根据32或者64位系统决定本身是 int 还是long) CGFloat(根据32或者64位系统决定是 float 还是double)
    • NSString NSNumber NSArray NSDate 都是指针类型的对象,在堆中分配内存,c 语言中的 char int 等都是在栈中分配空间
  3. id 和 nil 代表什么

    • id 类型的指针可以是任意类型的 OC对象
    • nil 代表空值(空指针的值,0)
  4. nil 和 NULL 的区别

    • 从 oc 的官方语法上看,nil 表示对象的指针,即对象的引用位空
    • NULL 表示指向基础数据类型的变量 即 c 语言变量的指针为空,是宏,表示空指针。
    • 在非 ARC 中两个值可以互换,在ARC 中普通指针和对象引用被严格限制,不能互换
    • nil 调用任何方法表示什么也不执行,也不会崩溃。是宏,表示对象为空。
    • Nil:代表((void *) 0) 。但是它是用于代表空类的。比如:Class class = Nil; 是宏,表示类指向空。
    • NSNull:继承与 NSObject,是一个空对象。是一个占位对象。
  5. __block/weak 修饰符区别

    • __block 在ARC和 MRC 下都能使用,可以修饰对象,也可以修饰基本类型。
    • __weak 只能在 ARC 下使用,只能修饰对象,不能修饰基本类型。
    • __block 对象可以在 block 中重新赋值,__weak 不行
  6. objc 中向一个对象发送消息[obj foo]和 objc_msgSend()函数之间有什么关系?

    • 实际上编译器会转成objc_msgSend:((void (*))(id, SEL))((void) objc_msgSend)((id)obj, sel_registerName("foo"));

相关文章

网友评论

      本文标题:objective-c 复习

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