前言:面试笔试都是必考语法知识点。请认真复习和深入研究OC。
obje-c
1. 方法和选择器有何不同?(Difference between method andselector?)
答:selector 只是一个方法的名字,method是一个组合体,包含了名字和实现。
2. Core Foundation的内存管理
答: 1.凡是带有Create、Copy、Retain等字眼的函数,创建出来的对象,都需要在最后做一次release 2.比如CFRunLoopObserverCreate release函数: CFRelease(对象);
【扩充]:
2.1 内存管理 Autorelease、retain、copy、assign的set方法和含义?1).你初始化(alloc/init)的对象,你需要释放(release)它。例如: NSMutableArray *aArray = [[NSArray alloc] init]; 后,需要 [aArray release]; 2).你retain或copy的,你需要释放它。例如: [aArray retain] 后,需要 [aArray release]; 3).被传递(assign)的对象,你需要斟酌的retain和release。例如: obj2 = [[obj1 someMethod] autorelease]; 对象2接收对象1的一个自动释放的值,或传递一个基本数据类型(NSInteger, NSString)时:你 或希望将对象2进行retain,以防止它在被使用之前就被自动 释放掉。但是在retain后,一定要 在适当的时候进行释放。 <扩展> 关于索引计数(Reference Counting)的问题 retain值 = 索引计数(Reference Counting) NSArray对象会retain任何数组中的对象(索引计数值retain+1)。当NSArray被摧毁(dealloc)的时候, 所有数组中的对象会 被 执行一次释放(索引计数值retain值 -1)。 不仅仅是NSArray,任何收集类 (Collection Classes)都执行类似操作。例如 NSDictionary, 甚至UINavigationController。Alloc/init建立的对象,索引计数为1。无需将其再次retain。 [NSArray array]和[NSDate date]等“方法”建立一个索引计数为1的对象,但是也是一个自动释放对象。 所以是本地临时对象,那么无所谓了。如果是打算在全Class中使用的变量(iVar), 则必须retain它。 缺省(系统默认的)的类方法返回值都被执行了“自动释放”方法。(*如上中的NSArray) 在类中“dealloc”方法中,release所有未被平衡(未被释放)的NS对象。(所有未被autorelease, 而retain值为1的)
3. malloc和New的区别
答: 1.new是c++中的操作符,malloc是c中的一个函数 2.new 不止是分配内存,而且会调用类的构造函数,同理delete会调用类的析构函数。 而malloc则只分配内存,不会进行初始化类成员的工作,同样free也不会调用析构函数。 3.内存泄露对于malloc或者new都可以检查出来的,区别在于new可以指定哪个文件的哪一行,而malloc没有这些消息。 4.new和malloc效率的比较高 5.new出来的指针是直接带类型信息的。
参考文章: 细说new与malloc的10点区别
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 = NSSelectorFromString(@"setName") [stu performSelector:selector withObject:@"Mike"]; 2.将方法变成字符串 NSStringFromSelector(@selector*(setName:))
5. 什莫是SEL?如何声明一个SEL?通过哪些方法能够,调用SEL包装起来的方法?
答: 1.SEL就是对方法的一种包装。包装的SEL类型数据,它对应相应的方法地址,找到方法地址就可以调用方法。 在内存中每个类的方法都存储在类对象中,每个方法都有一个与之对应的SEL类型的数据,根据一个SEL数据 就可以找到对应的方法地址,进而调用方法。 2.怎么包装 SEL s1 = @selector(test1); //将test1方法包装成SEL对象 SEL s2 = NSSelectorFromString(@"test1");// 将一个字符串方法转换成SEL对象 3.调用方式 1)直接通过方法名来调用[person text]; 2) 间接的通过SEL数据来调用SEL aaa = @selector(text);[person performSelector:aaa];
6. 协议中<NSObject>是什莫意思?子类继承了父类,那么子类会遵守父类的协议吗?协议中能够定义成员变量吗?如何约束一个对象类型的变量要存储的地址是遵守一个协议对象?
- 遵守NSObject协议 - 会 - 能,但是只在头文件中声明,编译器是不会自动生成实例变量的。需要自己处理getter和setter。 - id <xxx>
7. NS/CF/CG/CA/UI这些前缀分别是什莫含义?
- NS-->函数归属属于cocoa Fundation框架 - CF-->函数归属属于core Fundation框架 - CG-->函数归属属于Core Graphics.frameworks框架 - CA-->函数归属属于CoreAnimation.frameworks框架 - UI-->函数归属属于UIKit框架
8. 面向对象都有哪些特征以及你对这些特征的理解。
- 继承:继承是从已有类得到继承信息创建新类的过程。提供继承信息的类被称为父类(超类、基类); 得到继承信息的类被称为子类(派生类)。继承让变化中的软件有了一定的延续性,同时继承 也是封装程序中可变因素的重要手段。
- 封装:*
封装是把数据和操作的方法绑定起来,对数据的访问只能通过已定义的接口。我们在类中编写的 方法就是对实现细节的一种封装;我们编写一个类就是对数据和操作的封装。可以说,封装就是 隐藏一切可隐藏的东西,只向外界提供最简单的编程接口。
- 多态:
多态性是指允许不同的子类型的对象对同一消息做出不同的响应。简单的说就是用同样的对象引 用调用同样的方法但是做了不同的事情。多态性分为编译时的多态性和运行时的多态性。方法重载 (overload)实现的是编译时的多态性(也称为前绑定),而方法重写(override)实现的是运行时的多 态性(也称后绑定)。运行时的多态是面向对象最精髓的东西,要实现多态需要做两件事情: 1.方法重写(子类继承父类并重写父类中已有的或抽象的方法); 2.对象造型(用父类型引用子类型对象,这样 同样的引用调用同样的方法就会根据子类对象的不同而表现出不同的行为)。
- 抽象:
抽象是将一类对象的共同特征总结出来构造类的过程。包括数据抽象和行为抽象两方面。抽象只关注 对象有哪些属性和行为,并不关注这些行为的细节是什莫。
9. 我们说的Objective-C是动态运行时语言是什莫意思?
- 主要是将数据类型的确定由编译时,推迟到了运行时。这个问题其实浅涉及到两个概念,运行时和多态。 - 简单来说,运行时机制使我们直到运行时才去决定一个对象的类别,以及调用该类别对象指定的方法。 - 多态:不同对象以自己的方式响应相同消息的能力叫多态。 - 意思就是假设生物类(life)都拥有一个相同的方法-eat;那人类属于生物,猪也属于生物,都继承了life后, 实现各自的eat,但是调用是我们只需调用各自的eat方法。也就是不同的对戏那个以自己的方式响应了相同的 消息(响应了eat这个选择器)。因此也可以这么说,运行时机制是多态的基础。
10. readwrite, readonly, assign, retain, copy, nonatomic属性的作用?
1) @property是一个属性访问声明,扩号内支持以下几个属性: 2) getter=getterName,setter=setterName,设置setter与 getter的方法名 3) readwrite,readonly,设置可供访问级别 4).assign,setter方法直接赋值,不进行任何retain操作,为了解决原类型与环循引用问题。 用于非指针变量。用于基础数据类型 (例如NSInteger)和C数据类型(int, float, double, char, 等), 另外还有id,其setter方法直接赋值,不进行任何retain操作. 5).retain,setter方法对参数进行release旧值再retain新值,所有实现都是这个顺序(CC上有 相关资料) 6).copy,setter方法进行Copy操作,与retain处理流程一样,先旧值release,再 Copy出新的 对象,retainCount为1。这是为了减少对上下文的依赖而引入的机制。 7).nonatomic,决定编译器生成的setter getter是非原子操作,非原子性访问,不加同步,多 线程并发访问会高性能。注意,如果不加此属性,则默认是两个访问方法都为原子型事务访 问。锁被加到所属对象实例级。 8).weak 用于指针变量,比assign多了一个功能,当对象消失后自动把指针变成nil,由于消息发 送给空对象表示无操作,这样有效的避免了崩溃(野指针),为了解决原类型与循环引用问题 9).strong 用于指针变量,setter方法对参数进行release旧值再retain新值 - readwrite 是可读可写特性,需要生成getter方法和setter方法; - readonly 是只读特性 只会生成getter方法 不会生成setter方法,不希望属性在类外改变; - assign 是赋值特性,setter方法将传入参数赋值给实例变量;仅设置变量;assign用于简单数据类型,如NSInter,double,bool; - retain 表示持有特性,setter方法将传入参数先保留,在赋值,传入参数的引用计数器retaincount+1; - copy 表示赋值特性,setter方法将对象赋值一份;需要完全一份新的变量时; - nonatomic 非原子操作,决定编译器生成的setter getter 是否是原子操作; - atomic 表示多线程安全,一般使用notatomic
11. 简述NotificationCenter、KVC、KVO、Delegate?并说明它们之间区别(重点)
- KVO (Key-Value-Observing):
一对多,观察者模式,键值观察机制,它提供了观察某一属性变化,极大简化了代码。
- KVC(Key-Value-Coding):
键值编码,一个对象在调用setValue的时候, ① 检查是否存在相应key的set方法,存在就调用set方法。 ② set方法不存在,就查找_key的成员变量是否存在,存在就直接赋值。 ③ 如果_key没找到,就查找相同名称的key,存在就赋值。 ④ 如果没有就调用valueForUndefinedkey和setValue: forUndefinedKey。
- Delegate:
通常发送者和接受者的关系是直接的一对一的关系。 ① 代理的目的是改变或者传递控制链。允许一个类在某些特定时刻通知到其他类,而不需要获取到那些类的指针。 ② 可以减少框架复杂度。消息的发送者(sender)告知接受者(receive)某个事件将要发生,delegate后,发送者响应事件, delegate机制使得接收者可以改变发送者行为。
- Notification:
观察者模式,通常发送者和接受者的关系是间接的多对多关系。 消息的发送者告知接收者事件已经发生或者将要发送,仅此而已,接受者并不能反过来想想发送者的行为。
-区别:
① 就效率来说,delegate比NSNotification高。 ② delegate方法比notification更加直接,需要关注返回值,所以delegate方法往往包含should这个传奇的词。 相反的,notification最大的特色就是不关心结果。所以notification往往用did这个词汇。 ③ 两个模块之间联系不是很紧密,就用notification传值,例如多线程之间传值用notification。 ④ delegate只是一种较为简单的回调,且主要用在一个模块中,例如底层功能完成了, 需要把一些值传到上层去,就事先把上层的函数通过delegate传到底层, 然后在底层call这个delegate,它们都在一个模块中,完成一个功能, 例如说NavgationController从B界面到A点返回按钮(调用popViewController方法) 可以用delegate比较好。
12. 懒加载 (What is lazy loading ?)
- 就是懒加载,只是在用到的时候才去初始化。也可以理解为延迟加载。 我觉得最好也是最简单的一个例子,就是tableView中图片的加载显示, 一个延时加载,避免内存过高,一个异步加载,避免线程堵塞提高用户体验。
13. OC有多继承吗?没有的话可以用什莫方法替代
- 多继承即一个子类可以有多个父类,它继承了多个父类特性。 - Object-c的类没有多继承,只支持单继承,如果要实现多继承的话,可以通过类别和协议来实现。 - protocol (协议) 可以实现多个接口,通过实现多个接口可以完成多继承。 - Category (类别) 一般使用分类,用Category去重写类的方法,仅对本Category有效。不会影响到其他类与原有类的关系。
14. 分别描述类别(categories)和延展(extensions)是什莫?以及两者的区别?继承和类别在实现中有何区别?为什么category只能为对象添加方法,却不能添加成员变量?
- 类别:在没有原类 .m 文件的基础上,给该类添加方法; - 延展:一种特殊形式的类别,主要在一个类的.m文件里声明和实现延展的作用,就是给某类添加私有方法或是私有变量。 - 两个的区别: ① 延展可以添加属性并且它的方法都是不需实现的。延展可以认为是一个私有的类目。 ② 类别可以在不知道,不改变原有代码的情况下往里面添加新的方法,只能添加,不能删除修改。 ③ 并且如果类别和原来类中的方法产生名称冲突,则类别将覆盖原来的方法,因为类别具有更高的优先级。 ④ 继承可以增加,修改删除方法,添加属性。 - Category只能为对象添加方法,却不能添加成员变量。原因:如果可以添加成员变量,添加的成员变量没有办法初始化。
15. Objective-C有私有方法吗?私有变量呢?如没有的话,有没有什莫代替的方法?
- Objective-c类里面的方法只有两种,静态方法和实例方法。但是可以通过把方法的声明和定义 都放在.m文件中来实现一个表面上的私有方法。有私有变量,可以通过@private来修饰, 或者把声明放到.m文件中。在Objective-c中,所有实例变量默认都是都是私有的, 所有实例方法默认都是公有的。
16. include与#import的区别?#import与@class的区别
- import 是 Objective-C 导入头文件的关键字,#include 是 C/C++导入头文件的关键字 - 使用import 头文件会自动只导入一次,不会重复导入,相当于#include 和#pragma once;(条件编译) - import指令就是Object-C针对#include的改进版本,#import确保引用的头文件只会被引用一次,这样你就不会陷入递归包含的问题中。 - @class 告诉编译器某个类的声明,当执行时,才去查看类的实现文件,循环引用头文件;#import<> 用来包含系统的头文件,#import””用来包含用户头文 - import与@class二者的区别在于: ① import会链入该头文件的全部消息,包括实例变量和方法等。而@class只是告诉编译器,其后面声明的名称是类的名称,至于这些类是如何定义的,暂时不用考虑。 ② 在头文件中一般使用@class来声明这个名称是类的名称,不需要知道其内部的实体变量和方法。 ③ 而在实现类里面,因为会用到这个引用类的内部的实体变量和方法,所以需要使用#import来包含这个被引用类的头文件。 ④ 在编译效率方面,如果你有100个头文件都#import了同一个头文件, 或者这些头文件是依次引用的,如A->B,B->C,C->D这样的引用关系。 当最开始的头文件有变化的话,后面所有引用它的类都需要重新编译, 如果你有的类很多的话,这将耗费大量的时间。而是用@class则不会。 ⑤ 如果有循环依赖关系,如:A->B,B->A这样的相互依赖关系,如果使用 #import来相互包含,那么就会出现编译错误,如果使用@class在两个类的头 文件中相互声明,则不会有编译错误出现。
17. 浅复制(拷贝)和深复制的区别?
- 浅复制(copy):只复制指向对象的指针,而不复制引用对象本身。 - 深复制(mutableCopy): 复制引用对象本身。深复制就好理解了,内存中存在了两份独立对象本身,当修改A时,A_copy不变。
18. 类变量的@protected,@private,@public,@package声明各有什莫含义?
变量的作用域不同。 - @protected 该类和子类中访问,是默认的; - @private 只能在本类中访问; - @public 任何地方都能访问; - @package 本包内使用,跨包不可以;
19. Objective-C和C、C++之间的联系和区别?
- Objective-C和C++都是C的面向对象的超集。 - Objective与C++的区别主要点: Objective-C是完全动态的,支持在运行时 动态类型决议(dynamic typing),动态绑定(dynamic binding)以及动态装载 (dynamic loading);而C++,是部分动态的,编译时静态绑定,通过嵌入 类(多重继承)和虚函数(虚表)来模拟实现。 - Objective-C在语言层次上支持动态消息转发,其消息发送语法为[object function]; 而且C++为object->function()。两者的语义也不同,在Objective-C里是说发送 消息到一个对象上,至于在这个对象能不能响应消息以及是响应还是转发消息都不会 crash;而在C++里是说对象进行了某个操作,如果对象没有这个操作的话,要么编 译会报错(静态绑定),要么程序会crash掉的(动态绑定)。
20. 目标-动作机制
- 目标是动作消息的接收者。一个控件,或者更为常见的是它的单元,以插座变量的形式保其动作消息的目标。 - 动作是控件发送给目标的消息,或者从目标的角度看,它的目标为了响应动作而实现的方法。程序需要某些机制来进行事件和指令的翻译。 这个机制就是目标-动作机制。
- 21. Objective-C优点和缺点
- 优点:
① Cateogies
② Posing
③ 动态识别
④ 指标计算
⑤ 弹性讯息传递
⑥ 不是一个过度复杂的C衍生语言
⑦ Objective-C与C++可混合编程
- 缺点
① 不支持命名空间
② 不支持运算符重载
③ 不支持多重继承
④ 使用动态运行时类型,所有的方法都是函数调用,所以很多编译时优化方法都用不到。(如内联函数等),性能低劣。
- 22. C语言的函数调用和oc的消息机制有什莫区别?
- 对于C语言,函数的调用在编译的时候会决定调用哪个函数。编译完成之后直接顺序执行。
- OC的函数调用成为消息发送。属于动态调用过程。在编译的时候并不能决定真正调用哪个函数
(事实证明,在编译阶段,OC可以调用任何函数,即使这个函数并未实现,只要申明过就不会报错。而C语言在编译阶段就会报错)。这有在真正运行的时候才会根据函数的名称找到对应的函数来调用。
23. 什么是谓词?
谓词就是通过NSPredicate给定的逻辑条件作为约束条件,完成对数据的筛选。// 定义谓词对象,谓词对象中包含了过滤条件 NSPredicate *predicate = [NSPredicate predicateWithFormat:@''age<%d'',30]; // 使用谓词条件过滤数组中的元素,过滤之后返回查询的结果 NSArray *array = [persons filteredArrayUsingPredicate:predicate]; // 可以使用&&进行多条件过滤 predicate = [NSPredicate predicateWithFormat:@''name='1' && age>40'']; array = [persons filteredArrayUsingPredicate:predicate]; // 包含语句的使用 predicate = [NSPredicate predicateWithFormat:@''self.name IN{'1','2','4'} || self.age IN{30,40}'']; // 指定字符开头和指定字符串结尾,是否包含指定字符 // name以a开头的 predicate = [NSPredicate predicateWithFormat:@''name BEGINSWITH 'a''']; // name以ba结尾的 predicate = [NSPredicate predicateWithFormat:@''name ENDSWITH'ba''']; // name中包含字符a的 predicate = [NSPredicate predicateWithFormat:@''name CONTAINS 'a''']; // like进行匹配多个字符 // name中只要有s字符就满足条件 predicate = [NSPredicate predicateEithFormat:@''name like 's''']; //?代表一个字符,下面的查询条件是: name中第二个字符是s的 predicate = [NSPredicate predicateWithFormat:@''name like '?s'''];
- 24. C与OC混用
处理.m可以识别c和oc,.mm可以识别c c++ oc 但是cpp只能用c/c++
- 25. atomic和nonatomic的区别
- atomic提供多线程安全,防止读写未完成的时候被另外一个线程的读写,造成数据错误。
- nonatomic在自己管理内存环境中,解析的访问器保留并自动释放返回值,若指定了nonatomic,那么访问器只是简单的返回这个值。
- 26. 常见的oc数据类型哪些,和c的基本类型有啥区别
- 常见的: NSInteger、 CGFloat、 NSString、 NSNumber、 NSMutableArray、 NSArray、 NSDate
- NSInteger 根据32或者64位系统决定本身是int还是long
- CGFloat 根据32或者64位系统决定本身是float还是double
- NSString NSNumber NSArray NSDate是指针类型的对象,在堆中分配内存,C语言中的char int 等都是在栈中分配控件
- 27. id和nil代表什么
- id类型的指针可以指向任何OC对象
- nil代表空值(空指针的值,0)
- 28. nil和NULL的区别
- 从oc的官方语法上看,nil表示对象的指针 即对象的引用为空
- null表示指向基础数据类型变量 即c语言变量的指针为空
- 在非arc中 两个空可以互换,但是arc中普通指针和对象引用被严格限制,不能互换
29. nil、Nil、NULL和NSNull区别
- nil和C语言的NULL相同,在objc/objc.h中定义。nil表示Objective-C对象的值为空。 在C语言中,指针的控制用NULL表示。在Objective-C中,nil对象调用任何方法表示什莫 也不执行,也不会崩溃。 - Nil: 那么对于我们Objective-C开发来说,Nil也就代表((void *)0)。但是它是用于代表空类的.比如:Class myClass = Nil; - NULL:在C语言中,NULL是无类型的,只是一个宏,它代表空。这就是在C/C++中的空指针。对于我们Objective-C开发来说,NULL就表示((void*)0) - NSNull:NSNull是继承于NSObject的类型。它是很特殊的类,它表示是空,什么也不存储, 但是它却是对象,只是一个占位对象。使用场景就不一样了,比如服务器中的接口中让我们在值为空时,传空。 NSDictionry *parameters = @{@''arg1'':@''value1'',@''arg2'':arg2.isEmpty?[NSNull null]:arg2};
对于NULL、nil、Nil这三者对于Objective-C中值是一样的,都是(void )0,那么为什么要区分呢?又与NSNull之间有什么区别:((void *)0)
- NULL是宏,是对于C语言指针而使用的,表示空指针 - nil是宏,是对于Objective-C中对象而使用的,表示对象为空 - Nil是宏,是对于Objective-C中的类而使用的,表示类指针为空 - NSNull是类类型,是用于表示空的占位对象,与JS或者服务器端的null类似的含意。
- 30. 向一个nil对象发送消息会发生什么?
向nil发送消息是完全有效的-- 只是在运行时不会有任何作用。
如果一个方法返回值是一个对象,那么发送给nil的消息将返回0(nil)
如果方法返回值为指针类型
其指针大小为小于或者等于sizeof(void*),float,double,long double 或者long long 的整型标量,发送给nil的消息将返回0. 如果方法返回值为结构体,正如在《Mac OS X ABI 函数调用指南》, 发送给nil的消息将返回0.结构体中各个字段的值将都是0.其他的结构 体数据类型将不是用0填充。** 如果方法的返回值不是上述提到的几种情况,那么发送给nil的消息的返回值将是未定义的。
self.和self->的区别
- self.是调用get或者set方法 - self是当前本身,是一个指向当前对象的指针 - self->直接访问成员变量
31. 类方法和实例方法的本质区别和联系
类方法属于类对象 只能类对象调用 self是类对象 类方法可以调用其他类方法 类方法不能访问成员变量 类方法不能直接调用对象方法
实例方法
属于实例方法 实例对象调用 self是实例对象 实例方法可以调用实例方法 实例方法可以访问成员变量 实例方法可以调用类方法
32. __block/weak修饰符区别
- __block在arc和mrc环境下都能用,可以修饰对象,也能修饰基本数据类型 - __weak只能在arc环境下使用,只能修饰对象(NSString),不能修饰基本数据类型(int) - __block对象可以在block中重新赋值,__weak不行。
33. 写一个NSString类的实现
NSString *str = [NSString alloc]initWithCString:null TerminatedCString encoding:encoding];
34. 为什么标准头文件都有类似一下的结构?
ifndef __INCvxWorksh
define __INCvxWorksh
ifdef __cplusplus
extern ''C'' {
endif
ifdef __cplusplus
}
endif
endif**显然,头文件中的编译宏"indef INCvxWorksh、#define INCvxWorksh.#endif"的作用是防止该头文件被重复引用**
- 35. init和initwithobject区别(语法)
后者给属性赋值
36.@property 的本质是什么?ivar/getter/setter是如何生成并添加到这个类中的
@property的本质:@property = ivar(实例变量) + getter(取方法) + setter(存方法)
-『属性』(property)有两大概念:ivar(实例变量)、存取方法(access method = getter +setter)
ivar/getter/setter如何生成并添加到类中:
这是编译器自动合成的,通过@synthesize关键字指定,若不指定,默认为@synthesize propertyName = _propertyName; 若手动实现了getter、setter方法,则不会自动合成。 - 现在编译器已经默认为我们添加@sythesize propertyName = _propertyName; 因此不再需要手动添加了,除非你真的要改成员 变量。 - 生成getter方法时,会判断当前属性名是否有_,比如声明属性为@property(nonatomic,copy) NSString *_name; 那么所生成的成员变量就会变成_ _name,不过,命名都要有规范,是不允许声明属性是使用_开头的,不规范的命名, 在使用runtime时,会带来很多的不方便。
*37. 这个写法会出现什么问题:@property(copy) NSMutableArray array
- 没有指名为nonatomic,因此就是atomic原子操作,会影响性能。 - 该属性使用了同步锁,会在创建时生成一些额外的代码用于帮助编写编写多线程程序,这会带来性能问题。 - 通过声明nonatomic可以节省这些虽然很小,但是不必要额外开销。 - 在我们的应用程序中,几乎都是使用nonatomic来声明的, - 因此使用atomic并不能保证绝对的线程安全,对于要绝对保证线程安全的操作, - 还需要使用更高级的方式来处理,比如NSSpinLock/@syncronized等。 - 因此使用的是copy,所得到的实际是NSArray,它是不可变的,若使用中使用了增、删、改操作,则会crash。
38. @protocol和category中如何使用@property
在protocol中使用@property只会生成setter和getter方法声明,
我们使用的目的是希望遵守我协议的对象能实现该属性。category使用@property也是只会生成setter和getter的声明,
如果,我们真的需要caregory增加属性的实现,需要借助于运行时的两个函数:
objc_setAssociatedObject
objc_getAssociatedObject
39. @property中有哪些属性关键字
① 原子性(atomic,nonatomic) ② 读写(readwrite, readonly) ③ 内存管理(assign, strong, weak, unsafe_unretained,copy) ④ getter、setter
40.isa指针问题
- isa: 是一个Class类型的指针.每个实例对象有个isa的指针, 它指向对象的类,而class里也有个isa指针,指向meteClass(元类)。 元类保存了类方法的列表。当类方法被调用时,先会从本身查找类方法的实现, 如果没有,元类会向他父类查找该方法。同时注意的是:元类>(meteClass) 也是对象。元类也有isa指针,它的isa指针最终指向的是 一个根元类 (root meteClass).根元类的is指针指向本身 ,这样形成了一个封闭的内循环。
41.如何访问并修改一个类的私有属性?
- 一种是通过KVC获取 - 通过runtime访问并修改私有属性
42.如何为Class定义一个对外只读对内可读写的属性?
在头文件中将属性定义为readonly,在.m文件中将属性重新定义为readwrite
43.Objective-C中,meta-class指的是什莫?
meta-class是Class对象的类,为这个Class类存储类方法,当一个类发送消息时, 就去这个类对应的meta-class中查找那个消息,每个Class都有不同的meta-class, 所有的meta-class,所有的meta-class都使用基类的meta-class(假如类继承 NSObject,那么他所对应的meta-class也是NSObject)作为他们的类。
44.Objective-C的class是如何实现的?Selector是如何被转化为c语言的函数调用的?
当一个类被正确的编译过后,在这个编译成功的类里面,存在一个变量用于保存这个类的信息。 我们可以通过[NSClassFromString]或[obj class]。这样的机制允许我们在程序执行的过程中, 可以Class来得到对象的类,也可以在程序执行的阶段动态的生成一个在编译阶段无法确定的 一个对象。(isa指针)
- @selector()基本可以等同C语言的中函数指针,只不过C语言中,
可以把函数名直接赋给一个函数指针,而Object-C的类不能直接
应用函数指针,这样只能做一个@selector语法来取。@interface foo - (int)add:int val @end SEL class_func; // 定义一个类方法指针 class_func = @selector(add:int); @selector是查找当前类的方法,而[object@selector(方法名:方法参数..)]; 是取object对应类的相应方法。 查找类方法时,除了方法名,方法参数查询条件之一。 可以用字符串来找方法SEL 变量名 = NSSelectorFromString(方法名字的字符串) 可以运行中用SEL变量反向查出方法名字字符串。NSString *变量名 = NSStringFromSelector(SEL参数); 取到selector的值以后,执行seletor.SEL变量的执行。用performSelecor方法来执行。 [对象 performSelector:SEL变量 withObject:参数1 withObject:参数2];
45. 对于语句NSString obj = [NSData alloc]init];,编译时和运行时obj是什莫类型?
- 编译时是NSString类型,运行时是NSData类型
46. @synthesize和@dynamic分别有什么作用?
- @property有两个对应的词,一个是 @synthesize,一个是@dynamic. 如果@synthesize和@dynamic都没写,那么默认的就是@synthesize var = _var; - @synthesize 的语义是如果你没有手动实现 setter 方法和getter,那么编译器会自动为你加上这两个方法。 - @dynamic 告诉编译器:属性的setter 与getter方法由用户自己实现,不自动生成。(当然对于 readonly 的属性只需要提供getter即可)。 假如一个属性被声明为@dynamic var,然后你没有提供@setter方法和@setter方法, 编译的时候没问题,但是当程序运行到 instance.var = someVar,由 于缺setter方法会导致程序崩溃;或者当运行到someVar = Var时,由于缺 getter方法同样会导致崩溃。编译时没有问题,运行时才执行相应的方法, 这就是所谓的动态绑定。 有些存取是在运行时动态创建的,如在 CoreData 的 NSManagedObject 类使用的某些。 如果你想 这些情况下,声明和使用属性,但要避免缺少方法在编译时的警告, 你可以使用@dynamic 动态 指令,而不是@synthesize 合成指令。
47. NSString 的时候用copy和strong的区别?
oc中NSString为不可变字符串的时候,用copy和strong都只分配一次内存, 但是如果用copy的时候,需要先判断字符串是否是不可变字符串,如果是不可 变字符串,就不在分配空间,如果是可变字符串才分配空间。如果程序中用到 NSString的地方特别多,每一次都要先进行判断就会耗费性能,影响用户体验, 用strong就不会再进行判断,所以不可变字符串可以直接用strong.
- 48.NSArray、NSSet、NSDictionary、NSMutableArray、NSMutableSet、NSMutableDictionary的特性和作用(遇到copy修饰产生的变化)
特性:
**NSArray** 表示不可变数组,是有序元素集,只能存储对象类型,可通过>索引直接访问元素, 而且元素类型可以不一样,但是不能进行增、删、改操作;>NSMutableArray是可 变数组,能进行增、删、改操作。通过索引查询值很快,但是插入、删除等效率很低。 **NSSet** 表示不可变集合,具有确定性、互异性、无序性的特点,只能>访问而不能修改集合; NSMutableSet表示可变集合,可以对集合进行增、删、改操作。集合通过值查询很快, 插入、删除操作极快。 **NSDictionary** 表示不可变字典,具有无序性的特点,每个key对应的值是唯一的,可通过 key直接获取值;NSMutableDictionary表示可变字典,能对字典进行增、删、改操作。 通过key查询值、插入、删除值都很快。
作用:
- 数组用于处理一组有序的数据集,比如通常用的列表的dataSource要有序,可通过索引直接访问,效率高。 - 集合要求具有确定性、互异性、无序性,在iOS开发中是比较少使用到的。笔者也不清楚如何说明其作用 - 字典是键值对数据集,操作字典效率极高,时间复杂度为常量,但是值是无序的。在iOS中,常见的 JSON转字典,字典转模型就是其中一种应用。
49. 请把字符串2015-04-10格式化日期转为NSDate
NSString *timeStr = @"2015-04-10"; NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; formatter.dateFormat = @"yyyy-MM-dd"; formatter.timeZone = [NSTimezone defaultTimeZone]; NSDate *date = [formatter dateFromString:timeStr]; // 2015-04-09 16:00:00 +0000 NSLog(@"%@",date);
50. 在一个对象的方法里:self.name = @object;和name = @object有什么不同
- 这是老生常谈的话题了,实质上就是问setter方法赋值与成员变量赋值有什么不同。 通过点语法self.name实质上就是[self setName:@object];。而name这里是成员变量,直接赋值。 - 一般来说,在对象的方法里成员变量和方法都是可以访问的, 我们通常会重写Setter方法来执行某些额外的工作。比如说, 外部传一个模型过来,那么我会直接重写Setter方法,当模型 传过来时,也就是意味着数据发生了变化,那么视图也需要更新 显示,则在赋值新模型的同时也去刷新UI。这样也不用在额外提供方法了。
51. 怎样使用performSelector传入3个以上参数,其中一个为结构体
- (id)performSelector:(SEL)aSelector; - (id)performSelector:(SEL)aSelector withObject:(id)object; - (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
因为系统提供的performSelector的api中,并没有提供三个参数。因此,我们只能传数组或者字典,但是数组或者字典只有存入对象类型,而结构体并不是对象类型,那么怎么办呢?没有办法,我们只能通过对象放入结构作为属性来传过去了:
typedef struct HYBStruct{ int a; int b; } *my_struct @interface HYBObject: NSObject @property (nonatomic,assign) my_struct arg3; @property (nonatomic,copy) NSString *arg1; @property (nonatomic,copy) NSString *arg2; @end @implementation HYBObject // 在堆上分配的内存,我们要手动释放掉 - (void)dealloc { free(self.arg3); } @end
测试:
my_struct str = (my_struct)(malloc(sizeof(my_struct))) str->a = 1; str->b = 2; HYBObject *obj = [[HYBObject alloc] init]; obj.arg1 = @"arg1"; obj.arg2 = @"arg2"; obj.arg3 = str; [self performSelector:@selector(call:) withObject:obj]; // 在回调时得到正确的数据的 - (void)call:(HYBObject *)obj { NSLog(@"%d %d",obj.arg3->a,obj.arg->b); }
52. objc中向一个对象发送消息[obj foo]和objc_msgSend()函数之间有什么关系?
实际上,编译器在编译时会转换成objc_msgSend,大概会像这样: ((void (*)(id,SEL)) (void)objc_msgSend) ((id)obj,sel_registerName("foo")); 也就是说,[obj foo];在objc动态编译时,会被转换为:
objc_msgSend(obj,@selector(foo));
这样的形式,但是需要根据具体的参数类型及返回值类型进行相应的类型转换。
53. 下面的代码输出什么?
@implementation Son: Father
- (id)init {
self = [super init];
if(self){
NSLog(@"%@",NSStringFromClass([self class]));
NSLog(@"%@",NSStringFromClass([self class]));
}
return self;
}
@end// 输出 NSStringFromClass([self class]) = Son; NSStringFromClass([self class]) = Son;
这个题目主要是考察关于Object-c中对self和super的理解。我们都知道self是类的隐藏参数,指向当前调用方法的这个类的实例。那super呢?
很多人会想当然的认为super和self类似,应该是指向父类的指针吧!
这是很普遍的一个误区。其实super是一个Magic Keyword,它本质是一个编译器标志符,和self是指向的同一个消息接受者!他们两个的不同点在于:super会告诉编译器,调用class这个方法时,要去父类的方法,而不是本类里的。上面的例子不管调用[self class]还是[super class],接受当前的对象都是Son *xxx这个对象。
当使用self调用方法时,会从当前类的方法列表中开始查找,如果没有就从父类中再找。
而当使用super时,则从当前类的方法列表中开始找。然后调用父类这个方法。
54. 若一个类有实例变量NSString _foo,调用setValue:forKey时,可以以foo还是_foo作为key?
答:两者都可以
55. 什莫时候使用NSMutableArray,什莫时候使用NSArray?
答:- 当数组在程序运行时,需要不断变化的,使用NSMutableArray. - 当数组在初始化后,便不在改变时,使用NSArray.
需要指出
- 使用NSArray只表明该数组在运行时,不发生改变,即:不能往NSArray的数组中新增和删除元素,但不表明其数组内的内容不发生改变。 - NSArray是线程是安全的,NSMutableArray线程是不安全的,多线程使用> NSMutableArray需要注意。
56. 类NSObject的哪些方法经常被使用?
- NSObject是Object-C的基类,其由NSObject类及一系列协议组成 - 类方法 alloc /class/description - 对象方法 init/dealloc/-performSelector:withObject:afterDelay:等经常使用
57.什莫是简便构造方法
答:
简便构造方法一般由CocoaTouch框架提供,如NSNumber的
+numberWithBool: +numberWithChar: +numberWithDouble: +numberWithFloat; +numberWithWithInt
Foundation下大部分类均有简便构造方法,我们可以通过简便构造方法,获得系统给我们创建好的对象,并且不需要手动释放。
58.什莫是构造方法,使用构造方法需要什莫注意点?
- 什莫是构造方法:构造方法是对象初始化并一个实例方法。
- 构造方法有什莫用:一般在构造方法里,对类进行一些初始化操作
注意点:方法开头必须以init开头,接下来名称要大写 例如 initWithName,initLayout
59.创建一个对像需要经过三个步骤?
- 开辟内存空间
- 初始化参数
- 返回内存地址值
60.Get方法的作用是什莫?
Get方法的作用:为调用者返回对象内部成员变量
61.Set方法的作用是什莫?Set方法的好处是什莫?
- Set 方法的作用: 为外界提供一个设置成员变量值的方法。
- Set 方法的好处:
- 不让对象暴露在外,保证了数据的安全性
- 对设置的数据进行过滤
62.结构体中能定义oc对象吗?
不能,因为结构体中只能是类型的声明,不能进行分配空间
63.点语法的本质是什莫?写一个点语法的例子,并写上注释
- 点语法的本质,就是方法的调用,而不是访问成员变量。当使用点语法是,编译器会自动展开响应的方法。
注意:切记,点语法的本事是转换成相应的set 和get 方法,如果没有set和get方法,则不能使用点语法。
** 例如**
# 例如有一个Person类 通过@property定义了name和age属性,在提供一个run方法。 Person *person = [Person new]; person.name = @"Tom"; // 调用了person的setName方法 int age = person.age; // 调用了person的age方法(get) person.run // 调用了person的run方法
64.id类型是什莫,instancetype就是什莫,有什莫区别?
- id类型:万能指针,能作为参数,方法的返回类型。
- instancetype: 只能作为方法的范围类型,并且返回的类型是当前定义类的类类型。(特定类)
65.成员变量的命名以下划线开头的好处?
- 与get方法的方法名区分开来;
- 可以和一些其他的局部变量分开来,下划线开头的变量,通常都是类的成员变量。
66.下面这段代码有什莫问题吗?
@implementation Person
- (void)setAge:(int)newAge{
self.age = newAge;
}
@end
- 会造成死循环,会重复调用自己!self,age改为_age即可;
- 并且书写不规范:setter方法中的newAge应该为age
67.截取字符串『20 | http:ww.baidu.com』中『|』字符串前面和后面的数据,分别输出它们。
- NSString *str = @"20 | http:ww.baidu.com"; NSArray *array = [str componentsSeparatedByString:@" | "]; 输出截取后的字符串 for (int i = 0;i<[array count];i++){ NSLog(@"%d = %@",i,[array objectAtIndex:i]); }
68.写一个完整的代理,包括声明和实现
- 创建 @protocol MyDelagate @required - (void)eat :(NSString * )foodName; @optional - (void)run; @end - 声明 @interface person :NSObject<MyDelagate> - 实现 @implementation person - (void)eat:(NSString * )foofName { NSLog(@"吃:%@!",foodName); } - (void)run { NSLog(@"run"); } @end
69. isKindOfClass、isMemberOfClass、selector作用分别是什莫?
① isKindOfClass,作用是,某个对象属于某个类型或者继承自某个类型
② isMemberOfClass某个对象确切属于某个类型
③ selector:通过方法名,获取内存中函数的入口地址
70. 请分别写出SEL、Id、@的意思?
- SEL 是selector的一个 类型,表示一个方法的名字----就是一个方法的入口地址。
- id是一个指向任何一个继承了Object(或者NSObject) 类的对象。需要注意的是id是一个指针,所以在使用id的时候不需要加*
- @: 是OC中的指令符
70. unsigned int 和int有什莫区别。 假设int长度为65535,请写出unsigned int 和int的取值范围
int:基本整数,当字节数为2时 取值范围为-32768~32767,当字节数为4时 取>值范围是 负的2的31次方 到2的31减1
unsigned int:无符号基本整数,当字节数为2时 取值范围为 0~65535,当字>节书为4时 取值范围为0到2的32次
71. Foundation对象,Core Foundation对象有什么区别
Foundation对象是OC的,Core Foundation对象是C对象
数据类型之间的转换
- ARC:bridge_retained(持有对象所有权,F->CF)、bridge_transfer(释放对象所有权CF->F)
- 非ARC:__bridege
72. 编写一个函数,实现递归删除指定路径下的所有文件。
+ (void)deleteFiles:(NSString *)path{ // 1.判断文件还是目录 NSFileManager *fileManger = [NSFileManager defaultManager]; BOOL isDir = NO; BOOL isExist = [fileManger fileExistsAtPath:path isDirectory:&isDir]; if(isExist){ // 2.判断是不是目录 if(isDir) { NSArray *dirArray = [fileManger contentOfDirectoryAtPath:path error: nil]; NSString *subPath = nil; for ( NSString *str in dirArray){ subPath = [path stringByAppendingPathComponent:str]; BOOL issubDir = NO; [fileManger fileExistsAtExistsAtPath:subPath isDirectory:&issubDir]; [self deleteFiles: subPath]; }else{ NSLog(@"%@",path) [manager removeItenAtPath:filePath error:nil]; } }else{ NSLog(@"你打印的是目录或者不存在"); } } }
73.UITableview创建方式
(1)自定义高度
1>新建一个继承自UITableViewCell的类
2>重写initWithStyle:reuseIdentifier:方法
3>添加所有需要显示的子控件(不需要设置子控件的数据和frame, 子控件要添加到 contentView中)
4>进行子控件一次性的属性设置(有些属性只需要设置一次, 比如字体\固定的图片)
5>提供2个模型- 数据模型: 存放文字数据\图片数据 - frame模型: 存放数据模型\所有子控件的frame\cell的高度
6>cell拥有一个frame模型(不要直接拥有数据模型)
7>重写frame模型属性的setter方法: 在这个方法中设置子控件的显示数据和frame(2)自定义高度原理
A 手动计算
1> 由于heightForRow比cellForRow方法先调用,创建frame模型包含微博模型,重写微博模型 赋值set方法,提前计算cell子控件的frame并保存,heightForRow方法中取出frame模型中保存 的高度,实现自定义高度cell。
2> 设置最大尺寸、文本属性,根据文本内容计算正文内容展示尺寸
3> cellForRow中创建自定义cell包含frame属性,重写frame属性set方法创建cell子控件并赋 值frame模型保存的子控件尺寸
B. 自动计算
1> 首先设置行高使用autolayout自动计算并预估高度
2> 在stroboard中对cell内容进行自动布局,注意设置图片距离底部约束,cellForRow中创建 storyboard中对应标记的自定义cell
3> 由于正文内容的不确定性,设置label多行,拖线图片高度约束,根据图片有无,设置代码 设置高度约束
74.Swift和OC的区别
苹果宣称 Swift 的特点是:
(1)快速、现代、安全、互动,而且明显优于 Objective-C 语言 (2)可以使用现有的 Cocoa 和 Cocoa Touch 框架 (3)Swift 取消了 Objective C 的指针/地址等不安全访问的使用 (4)供了类似 Java 的名字空间(namespace)、泛型(generic)var、运算对象重载(operator overloading (5)Swift 被简单的形容为 “没有 C 的 Objective-C”(Objective-C without the C) (6) 为苹果开发工具带来了Xcode Playgrounds功能,该功能供强大的互动效果,能让Swift源代码在撰写过程中实时显示出其运行结果; (7) 基于C和Objective-C,而却没有C的一些兼容约束; (8) 采用了安全的编程模式; (9)界面基于Cocoa和Cocoa Touch框架; (10) 舍弃 Objective C 早期应用 Smalltalk 的语法,保留了Smalltalk的动态特性,全面 改为句点表示法 (11) 类型严谨 对比oc的动态绑定
75.在项目开发中常用 的开发工具有哪些
Instrument beyondCompare git corn stone application loadder idea(编写 h5 和 RN):
76.UITableView&UICollection
UICollectionView 是 iOS6 新引进的 API,用于展示集合视图,布局更加灵活,其用法类似 于 UITableView。而 UICollectionView、UICollectionViewCell 与 UITableView、 UITableViewCell 在用法上有相似 的也有不同的,下面是一些基本的使用方法:
对于 UITableView,仅需要 UITableViewDataSource,UITableViewDelegate 这两个协议,使用 UICollectionView 需要实现 UICollectionViewDataSource,UICollectionViewDelegate, UICollectionViewDelegateFlowLayout 这三个协议,这是因为 UICollectionViewDelegateFlowLayout 实际上是 UICollectionViewDelegate 的一个子协议, 它继承 了 UICollectionViewDelegate,它的作用是供一些定义 UICollectionView 布局模式 的函数
77.NSProxy&NSObject
NSObjetct:
NSObject协议组对所有的Object-C下的objects都生效。如果objects遵从该协议, 就 会被看作是 first-class object(s 一级类)。另外,遵从该协议的 objects 的 retain,release, autorelease 等方法也服从 objects 的管理和在 Foundation 中 定义的释放方法。
一些容器中的 对象也可以管理这些 objects,比如 说 NSArray 和 NSDictionary 定义的对象。 Cocoa 的根类 也遵循该协议,所以所有继承 NSObjects 的 objects 都有遵循该协议的特性。
NSProXY:
NSProxy 是一个虚基类,它为一些表现的像是其它对象替身或者并不存在的对象 定义一套 API。一般的,发送给代理的消息被转发给一个真实的对象或者代理本 身 load(或者将本身转换 成)一个真实的对象。
NSProxy 的基类可以被用来透明的转发消息或者耗费巨大的对象的 lazy 初始化。
78.传值通知&推送通知(本地&远程)
传值通知: 类似通知,代理,Block 实现值得传递
.
推送通知: 推送到用户手机对应的 App 上(主要是不再前台的情况),用户获得资源的一种 手段。普通情况下,都是客户端主动的 pull。推送则是服务器端主动 push。
.
本地通知: local notification,用于基于时间行为的通知,比如有关日历或者 todo 列表的 小应用。 另外,应用 如果在后台执行,iOS 允许它在受限的时间内运行,它也会发现本地通 知有用。 比如,一个应用,在后台运行,向应用的服务器端获取消息,当消息到达时,比如下 载更新版本的提示消息,通过本地通知机制通知用户。
本地通知是 UILocalNotification 的实例,主要有三类属性:
scheduled time:时间周期,用来指定 iOS 系统发送通知的日期和时间; notification type:通知类型,包括警告信息、动作按钮的标题、应用图标上的 badge(数 字标记)和播放的声音; 自定义数据:本地通知可以包含一个 dictionary 类型的本地数据。
对本地通知的数量限制,iOS 最多允许最近本地通知数量是 64 个,超过限制的本地通知将被 iOS 忽略。
远程通知(需要服务器)。流程大概是这样的
1> 生成 CertificateSigningRequest.certSigningRequest 文件 2> 将 CertificateSigningRequest.certSigningRequest 上传进 developer,导出.cer 文 件 3> 利用 CSR 导出 P12 文件 4> 需要准备下设备 token 值(无空格) 5> 使用 OpenSSL 合成服务器所使用的推送证书
一般使用极光/友盟推送,步骤是一样的,只是我们使用的服务器是极光的,不需要自己大服务 器!
79.第三方库&第三方平台
第三方库:一般是指大牛封装好的一个框架(库),或者第三方给我们供的一个库,这里 比较笼统 * 第三方平台:指第三方提供的一些服务,其实很多方面跟第三方库是一样的,但是还是存 在一些区别。 库:AFN,ASI,Alomofire,MJRefresh,MJExtension,MBProgressHUD 平台:极光,百度,友盟,Mob,环信
80.imageName 和 ImageWithContextOfFile 的区别?哪个性能高
用 imageNamed 的方式加载时,图片使用完毕后缓存到内存中,内存消耗多,加载速度快。 即使生成的对象被 autoReleasePool 释放了,这份缓存也不释放,如果图像比较大,或者图像 比较多,用这种方式会消耗很大的内存。
imageNamed 采用了缓存机制,如果缓存中已加载了图片,直接从缓存读就行了,每次就不 用再去读文件了,效率会更高 。
ImageWithContextOfFile 加载,图片是不会缓存的,加载速度慢。
大量使用 imageNamed 方式会在不需要缓存的地方额外增加开销 CPU 的时间.当应用程序需要 加载一张比较大的图片并且使用一次性,那么其实是没有必要去缓存这个图片的,用 imageWithContentsOfFile 是最为经济的方式,这样不会因为 UIImage 元素较多情况下,CPU 会 被逐个分散在不必要缓存上浪费过多时间.
81.NSCache&NSDcitionary
NSCache 与可变集合有几点不同:
NSCache 类结合了各种自动删除策略,以确保不会占用过多的系统内存。如果其它应用需 要内存时,系统自动执行这些策略。当调用这些策略时,会从缓存中删除一些对象,以最大限 度减少内存的占用。
NSCache 是线程安全的,我们可以在不同的线程中添加、删除和查询缓存中的对象,而不 需要锁定缓存区域。
不像 NSMutableDictionary 对象,一个缓存对象不会拷贝 key 对象。NSCache 和 NSDictionary 类似,不同的是系统回收内存的时候它会自动删掉它的内容。
(1)可以存储(当然是使用内存) (2)保持强应用, 无视垃圾回收. =>这一点同 NSMutableDictionary (3)有固定客户.
位运算
NSCache 特点:a> 线程安全的 b> 当内存不足的时候,自动释放 c> 缓存数量和缓存成本 区别NSMutableDictionary
区别NSMutableDictionary
1> 不能也不应该遍历 2> NSCache对key强引用,NSMutableDictionary对key进行copy
82.UIView 的 setNeedsDisplay 和 setNeedsLayout 方法
(1) 在 Mac OS 中 NSWindow 的父类是 NSResponder,而在 iOS 中 UIWindow 的父类是 UIVIew。 程序一般只有一个窗口但是会又很多视图。 (2) UIView 的作用:描画和动画,视图负责对其所属的矩形区域描画、 布局和子视图管理、 事件处理、可以接收触摸事件、事件信息的载体、等等。 (3) UIViewController 负责创建其管理的视图及在低内存的时候将他们从内存中移除。 还为标准的系统行为进行响应。 (4) layOutSubViews 可以在自己定制的视图中重载这个方法,用来调整子视图的尺寸和位置。 (5) UIView 的 setNeedsDisplay(需要重新显示,绘制)和 setNeedsLayout(需要重新布局)方 法。 首先两个方法都是异步执行的。而 setNeedsDisplay 会调用自动调用 drawRect 方法,这 样 可以拿到 UIGraphicsGetCurrentContext,就可以画画 了。而 setNeedsLayout 会默认调用 layoutSubViews,就可以处理子视图中的一些数据。 综上所述:setNeedsDisplay 方便绘图,而 layoutSubViews 方便出来数据。setNeedDisplay 告 知视图它发生了改变,需要重新绘制自身,就相当于刷新界面.
83.UILayer&UIView
UIView 是 iOS 系统中界面元素的基础,所有的界面元素都继承自它。1)它本身完全是由 CoreAnimation 来实现的(Mac 下似乎不是这 样)。 2)它真正的绘图部分,是由一个叫 CALayer(Core Animation Layer)的类来管理。 3)UIView 本身,更像是一个 CALayer 的管理器,访问它的跟绘 图和跟坐标有关的属性, 例如 frame,bounds 等等, 实际上内部都是在访问它所包含的 CALayer 的相关属性。 4)UIView 有个重要属性 layer,可以返回它的主 CALayer 实例。
UIView 的 CALayer 类似 UIView 的子 View 树形结构,也可以向它的 layer 上添加子 layer, 来完成某些特殊的表示。即 CALayer 层是可以嵌套的。
UIView 的 layer 树形在系统内部,被维护着三份 copy。 分别 shi 逻辑树:这里是代码可以操纵的; 动画树:是一个中间层,系统就在这一层上更改属性,进行各种渲染操作; 显示树:其 内容就是当前正被显示在屏幕上得内容。 动画的运作:对 UIView 的 subLayer(非主 Layer)属性进行更改, 系统将自动进行动画生 成,动画持续时间的缺省值似乎是 0.5 秒。 坐标系统:CALayer 的坐标系统比 UIView 多了一个 anchorPoint 属性, 使用 CGPoint 结构 表示,值域是 0~1,是个比例值。 渲染:当更新层,改变不能立即显示在屏幕上。当所有的层都准备好时, 可以调用 setNeedsDisplay 方法来重绘显示。 变换:要在一个层中添加一个 3D 或仿射变换,可以分别设置层的 transform 或 affineTransform 属性。 变形:Quartz Core 的渲染能力,使二维图像可以被自由操纵, 就好像是三维的。图像可以在一个三维坐标系中以任意角度被旋转, 缩放和倾斜。CATransform3D 的一套方法供了一 些魔术般的变换效果。
84.layoutSubViews&drawRects
layoutSubviews 在以下情况下会被调用(视图位置变化是触发):
1、init 初始化不会触发 layoutSubviews。 2、addSubview 会触发 layoutSubviews。 3、设置 view 的 Frame 会触发 layoutSubviews,当然前是 frame 的值设置前后发生了变 化。 4、滚动一个 UIScrollView 会触发 layoutSubviews。 5、旋转 Screen 会触发父 UIView 上的 layoutSubviews 事件。 6、改变一个 UIView 大小的时候也会触发父 UIView 上的 layoutSubviews 事件。 7、直接调用 setLayoutSubviews。
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。
drawRect 方法使用注意点:
1、 若使用 UIView 绘图,只能在 drawRect:方法中获取相应的 contextRef 并绘图。 如果 在其他方法中获取将获取到一个 invalidate 的 ref 并且不能用于画图。 drawRect:方法不能 手动显示调用,必须通过调用 setNeedsDisplay 或 者 setNeedsDisplayInRect, 让系统自动 调该方法。 2、若使用 calayer 绘图,只能在 drawInContext: 中(类似鱼 drawRect)绘制, 或者在 delegate 中的相应方法绘制。同样也是调用 setNeedDisplay 等间接 调用以上方法 3、若要实 时画图,不能使用 gestureRecognizer,只能使用 >touchbegan 等方法来掉用 setNeedsDisplay 实时刷新屏幕