1. 标识符的规则
- 字母、数字、下划线、美元符$,但是不能以数字开头;
- 区分大小写
- 不能是关键字
2. #import 和 #include 的区别
-
include 的作用就是将指定的源代码插入到当前源代码的位置,如果导致了重复导入,不会给出提示
- Objective-C 提供的 #import 更加智能,可以帮助程序员判断,避免重复导入的问题
3. OC 的块
OC 的块类似 Swift 的闭包,像一个匿名函数B,在定义的时候无须指定名字,通常的用法是作为函数A的参数,在调用 A 的时候实时定义 B,使得代码更加灵活:
#import
typedef void (^FKProcessBlock)(int); // 定义一个块类型
// 使用FKProcessBlock定义最后一个参数类型为块
void processArray(int array[]
, unsigned int len, FKProcessBlock process)
{
for(int i = 0 ; i < len; i ++)
{
process(array[i]); // 将数组元素作为参数调用块
}
}
int main(int argc , char * argv[])
{
@autoreleasepool{
int arr[] = {2, 4, 6}; // 定义一个数组
// 传入块作为参数调用processArray()函数
processArray(arr , 3 , ^(int num)
{
NSLog(@"元素平方为:%d" , num * num);
});//注意这里大括号中的是块的定义
}
}
4. id类型
id类型是Objective-C提供的一个特有类型,这个类型可以代表所有对象的类型,也就是说,任意类的对象都可以赋值给id类型的变量
当通过id类型的变量来调用方法时,Objective-C会执行动态绑定,在程序运行时自动判断对象所属的类,确定需要动态调用的方法
5. 单例模式 Singleton
某些时候,我们要使用的类只用到一个实例,例如一个窗口管理器,这时候就可以用到单例类,保证这个类始终只能创建一个对象。常用写法:
// 接口部分
#import
@interface Singleton : NSObject
+(instancetype) shareInstance ;
@end
// 实现部分
#import "Singleton.h"
@implementation Singleton
/*
用 static 全局变量实现,每次程序获取该实例前都要先判断该 static 全局变量是否为 nil:
如果为 nil 就初始化实例;
如果不为 nil,程序直接返回该全局变量指向的实例。
*/
static Singleton* _instance = nil;
+(instancetype) shareInstance
{
static dispatch_once_t onceToken ;
dispatch_once(&onceToken, ^{
_instance = [[self alloc] init] ;
}) ;
return _instance ;
}
@end
// 测试程序
#import "Singleton.h"
int main(int argc , char * argv[]) {
@autoreleasepool{
// 判断两次获取的实例是否相等,程序将返回1(代表真)
NSLog(@"%d", [Singleton instance] == [[Singleton instance];
}
}
测试程序如下
6. 访问控制符
OC中提供了4个访问控制符:@private @package @protected @public。
- @private(当前类访问权限):成员只能在当前类内部可以访问,在类实现部分定义的成员变量相当于默认使用了这种访问权限。
- @package(同映像访问权限):成员可以在当前类或和当前类实现的同一映像中使用。同一映像就是编译后生成的同一框架或同一个执行文件。
- @protected(子类访问权限):成员可以在当前类和当前类的子类中访问。在类接口部分定义的成员变量默认是这种访问权限。
- @public(公共访问权限):成员可以在任意地方访问。
@private | @packge | @protected | @public | |
---|---|---|---|---|
同一个类中 | √ | √ | √ | √ |
同一个映像中 | √ | √ | ||
子类中 | √ | √ | ||
全局范围 | √ |
7. 合成存取 @property
系统自动合成 setter 和 getter 方法:
- 在接口部分 @interface 和 @end 之间使用 @property指令 定义属性(无须放在花括号中);
- (可选)在类实现部分使用 @synthesize指令 改变对应的成员变量名。
8. @property 指示符
①. atomic/nonatomic 线程管理
指定合成存取方法是否为原子操作,可以理解为是否线程安全,但在iOS上即时使用atomic也不一定是线程安全的。
可以发现几乎所有代码的属性设置都会使用nonatomic,这样能够提高访问性能,在iOS中使用锁机制的开销较大,会损耗性能。
②. readwrite/readonly 读写端丽
- readwrite是编译器的默认选项,表示自动生成getter和setter,如果需要getter和setter不写即可。
- readonly表示只合成getter而不合成setter。
③. assign,retain,strong,weak,copy,unsafe_unretained 内存管理
- assign: 简单赋值,不更改索引计数(Reference Counting)。适用于基础类型(简单类型,原子类型):NSInteger,CGPoint,CGFloat,C数据类型(int,float,double,char等)。
- retain:释当把某个对象赋值给该属性时,该属性原来所引用的对象的引用计数减1,被赋值对象的引用计数加1。在未启用ARC机制的的情况下,retain可以保证一个对象的引用计数大于1时,该对象不会被回收。启用ARC后一般较少使用retain。
- strong 指示符该属性对被赋值对象持有强引用,强引用的意思是:只要该强引用指向被赋值的对象,那么该对象就不会自动回收。
- weak 指示符该属性对被赋值对象持有弱引用,弱引用的意思是:即使该弱引用指向被赋值的对象,该对象也可能被回收。
- copy:如果使用copy指示符,当调用setter方法对成员变量赋值时,会将被赋值的对象复制的一个副本,再将该副本给成员变量,相应的原先的被赋值的对象的引用计数加1。当成员变量的类型是可变类型,或其子类是可变类型,被赋值的对象在赋值后有可能再被修改,如果不需要这种修改,则可以考虑copy指示符。
- unsafe_unretained:与weak不同,被unsafe_unretained指针所引用的对象被回收后,unsafe_unretained指针不会被赋为nil,可能会导致程序出错。
9.类别,拓展
当你已经封装好了一个类(也可能是系统类、第三方库),不想在改动这个类了,可是随着程序功能的增加需要在类中增加一个方法,这时我们不必修改主类,只需要给你原来的类增加一个分类。
将一个大型的类拆分成不同的分类,在不同分类中实现类别声明的方法,这样可以将一个类的实现写到多个.m文件中,方便管理和协同开发。
@interface 主类类名(分类类名)
//不可以定义成员属性
@end
@implementation 主类类名(分类类名)
@end
扩展是分类的一种特殊形式,通常定义在主类.m文件中,扩展中声明的方法直接在主类.m文件中实现。
分类是不可以声明实例变量,通常是公开的,文件名是:主类名+分类名.h
扩展是可以声明实例变量,是私有的,文件名为:主类名_扩展标识.h,在主类的.m文件中#import该头文件
10.协议,委托
协议文件的创建
- 新建文件
- 选择iOS平台Source中的Object-C Fie
- 选择File Type为protocol,则可建立协议文件
协议文件的特征
- 协议文件为单一的.h文件
- 命名规则一般为”类名Delegate.h”
使用格式
.h文件中的格式为
#import
@protocol 类名Delegate
// 在此声明协议方法
// @requires修饰的声明方法,代理方必须实现
// @optional修饰的声明方法,代理方可以不实现
@end
使用方法
委托方将该协议文件导入自己的.h文件中,并添加一个遵守该协议的代理属性
注:就像一般把扩展写在.m文件中,而不单独建立一个扩展文件一样;一般开发中,不单独建立一个协议文件,而是将协议制定在委托方的.h文件中。