哨兵查找法
题目:在array中,查找item,返回index
正常写法中的判断条件有index&item。
使用哨兵,减少index的判断
{
index = arr.count - 1
originFirst = arr[0]
arr[0] = item
while(arr[index] != item) {
index—;
}
arr[0] = originFirst
return index > 0 ? index : -1
}
当数量达到万级别时,执行时间会出现差异。
Objective-C
- 采用消息结构,非函数调用。
- 消息结构是指运行时所执行的代码,由运行环境决定。
- 函数调用是指运行时所执行的代码,由编译器决定。
- 运行期会检查对象类型。
- 运行期组件,本质是动态库,包含了对象的数据结构和函数。
- 对象所占内存,分配在堆上;变量为指针,分配在栈上。
??为什么要设计成运行时语言?
响应多态。运行时是 多态的基础。
多态是指不同的对象按照自己的方式来响应相同的消息。
头文件
在类的头文件中,尽量少引用文件。
可以采用@class **向前声明。
使用#import,会引用到许多用不到的内容,增加编译时间。优点是可以解决相互引用的问题。
多用字面量语法,少用与之等价的方法
类型常量与#define
多使用类型常量,少用#define。
类型常量会进行类型的检查。
使用#define可能会出现多次被替换的场景,而且没有作用域的概念。
定义类型常量时,经常使用static+const。
static意味着该变量仅在定义该变量的编译单元中可见。
如果没有static,编译器会默认创建一个外部符号,导致变量在其他编译单元中可见。
使用static+const,保证编译器不会创建外部符号,而是会像#define一样,仅做替换。
如何将变量外部可见?
.h:extern NSString *const a;
.m:NSString *const a = @"aa";
枚举
使用枚举表示状态、选项、状态码。
enum AA {};
enum AA a = AA1;
typedef enum AA = A;
A a = AA1;
新式枚举:可以指明类型,如果不指定,编译器不清楚数据类型的大小,无法确定分配空间。
enum AA : NSInteger {};
通常我们在定义枚举时,使用了系统提供的辅助宏。
typedef NS_ENUM(NSUInteger, AA) {};
typedef NS_OPTIONS(NSUInteger, BB) {};
辅助宏用于判断是否采用新式枚举。
什么时候使用NS_OPTIONS?
凡是需要按位操作来组合的枚举,都要使用NS_OPTIONS。
因为代码在是否C++模式下编译,处理是不一样的。
在使用或|处理枚举类型时,C++认为枚举结果类型应该是底层的数据类型NSUInteger,而且不允许隐式转换成枚举类型。
eg:AA1 | AA2
得到的结果类型是NSUInteger,而不是AA3。NS_OPTIONS会区分C++模式编译和 非C++模式编译,在非C++编译模式下=NS_ENUM,而在C++模式下,则会进行特殊处理,保证结果类型。
在switch中,如果是处理枚举,最好不要使用default,这样在后期加入新枚举值时,可以提示开发人员进行处理。
属性
特质:
-
原子性
atomic/nonatomic,默认atomic,是否使用同步锁机制。并不是完全的线程安全,如果想保证线程安全,需要更深层次的锁。iOS上一般使用nonatomic,mac os上一般使用atomic。
-
读写权限
-
内存管理 strong、assign、weak、copy
使用属性,编译器会自动编写读写该属性的方法,这个过程叫做自动合成。
@dynamic:阻止自动合成
@synthesize:指定实例变量的名字
读取实例变量时,一般采用直接访问形式,设置时通过属性。优点:
- 不经过方法派发,速度快
- 绕过了为属性定义的内存管理
- 不会触发KVO
初始化方法 及dealloc时,可以通过实例变量,惰性初始化时,需要通过属性。
Q:为什么atomic不是完全的线程安全? A:atomic不能保证对象多线程的安全,它只是能保证你访问的时候给你返回一个完好无损的Value而已。只是保证了setter和getter方法的线程安全,其他操作不保证。
对象等同性
对象相等,hash值相同;hash相同,对象不一定相等。
isEqual+hash。
编写hash时,应该选用计算速度快且hash值碰撞几率低的算法。
关联对象
只有在其他办法不行时,再使用关联对象,主要缺点是不易查找问题。
设置关联对象时,key通常使用 静态全局变量。
关于关联对象,见文章关联对象。
对象
类型为id的对象,编译器假定它能响应所有消息。
在运行期检查对象类型,又叫做 类型信息查询(内省)。
不要直接比较对象所属的类,应该通过类型信息查询。因为某些对象可能实现了消息转发功能,eg:代理对象。
每个oc对象实例,其实是指向内存数据的指针,所以带*。
isMemberOfClass:是否是某个特定类的实例。
isKindOfClass:是否是某个类或其派生类的实例。
缓存
构建缓存时选用NSCache 而非NSDictionary。
当系统资源耗尽时,NSCache可以自动删减缓存。
如果是普通的字典,则要自己编写手工删减缓存代码。
NSCache还会先删减最久未使用的对象。
NSCache是线程安全的。
内存管理
见文章小整内存管理。
Block
见文章开发必备-Block。
GCD
见文章开发必备-多线程。