1.OC为C语言添加了面向对象特性,是其超集。OC使用动态绑定的消息结构,也就是说,在运行时才会检查对象类型。接收一条消息后,究竟应执行何种代码,由运行期环境而非编译器决定。
2.在类的头文件中尽量少引用其他头文件
- 除非有必要,否则不要引入头文件,应在.h中使用@class声明别的类,并在.m中引入该类的头文件。这样做可以降低类之间的耦合。
- 有时无法使用@class声明,比如要声明某个类遵循一项协议。这种情况下,尽量把“该类遵循某项协议”的这条声明移至“分类中”
3.多用字面量语法(@[@"xx"]);
用字面量语法创建数组或字典时,若值中又nil,则会抛出异常。因此,务必确保值里不含nil。
4.多用类型常量,少用#define预处理指令 - 不要用与预处理指令定义常量。这样定义出来的常量不含类型信息,编译器只是会在编译前据此执行查找与替换操作。即使有人重新定义了常量值,编译器也不会产生警告信息,这将导致应用程序中的常量值不一致。
只在.m中使用,可这样定义:
static const NSTimeInterval kAnimationDuration = 0.3;
若要让外部使用,如下:
.h
extern NSString *const EOCStringConstant;
.m
NSString *const EOCStringConstant = @"xxx";
5.用NS_ENUM与NS_OPTIONS宏来定义枚举类型。在处理枚举类型的switch语句中不要事先default分支。这样的话,加入新枚举之后,编译器就会提示开发者:switch语句并未处理所有枚举。
6.在对象内部读取数据时,应该直接通过实例变量来读,而写入数据时,则应通过属性来写。
- 在初始化及dealloc方法中,总是应该直接通过实例变量来读写数据。
7.创建类簇
首先定义抽象基类:
typedef NS_ENUM(NSUInteger,EOCEmployeeType) {
EOCEmployeeTypeDeveloper,
EOCEmployeeTypeTypeDesigner,
EOCEmployeeTypeFinace,
};
抽象基类.m
+(EOCEmployee *)employeeWithType:(EOCEmployeeType)type {
switch (type) {
case EOCEmployeeTypeDeveloper:
return [EOCEmployeeDeveloper new];
break;
case EOCEmployeeTypeDesigner:
return [EOCEmployeeDeveloper new];
break;
case EOCEmployeeTypeFinace:
return [EOCEmployeeDeveloper new];
break;
}
}
-(void)doADaysWork {
}
// 子类
-(void)doAdaysWork {
[self writeCode];
}
命名规范
8.如果方法的返回值是新创建的,那么方法名的首个词应是返回值的类型,除非前面还有修饰语,例如localizedString。属性的存取方法不遵循这种命名方式。
9.应该把表示参数类型的名词放在参数前面。
10.如果方法要在当前对象上执行操作,那么就应该包含动词;若执行操作时还需要参数,则应该在动词后面加上一个或多个名词。
11.不要使用str这种简称,应该用string这样的全程。
12.boolean属性应加is前缀。如果某方法返回非属性的boolean值,那么应该根据其功能,选用has或is当前缀。
13.copy&mutableCopy
深拷贝的意思就是:在拷贝对象时,将其底层数据也一并复制过去。Foundation框架中所有的collection类在默认情况下都执行浅拷贝,也就是说,只拷贝容器对象本身,而不复制其中数据。
- (instancetype)initWithXing:(NSString *)xing ming:(NSString *)ming {
if (self = [super init]) {
_xing = [xing copy];
_ming = [ming copy];
_friends = [NSMutableArray array];
}
return self;
}
- (id)copyWithZone:(NSZone *)zone {
Person *person = [[Person allocWithZone:zone] initWithXing:_xing ming:_ming];
// person.friends = [[NSMutableArray alloc] initWithArray:_friends copyItems:YES];
person.friends = [_friends mutableCopy];
return person;
}
14.将方法响应能力缓存起来的最佳途径是使用“位段”数据类型。这是一项乏人问津的C语言特性。我们可以把结构体中某个字段所占用的二进制位个数设为特定的值。例如:
struct data {
unsigned int fieldA : 8;
unsigned int fieldB : 4;
unsigned int fieldC : 2;
unsigned int fieldD : 1;
};
在结构体中,fieldA位段将占用8个二进制位,fieldB占用4个,fieldC占用两个,fieldD占用1个。这样fieldD可表示0或1两个值。我们可以像fieldD这样,吧委托对象是否实现了协议中的相关方法这一信息缓存起来。次结构体用法如下:
@interface NetWorkFetcher() {
struct {
unsigned int didReceiveData : 1;
unsigned int didFailWithError : 1;
unsigned int didUpdateProgressTo : 1;
} _delegateFlags;
}
@end
该结构体含有三个位段,每个位段都与delegate所遵从的协议中某个可选方法相对应,用来缓存委托对象是否能响应特定的选择子。在NetworkFecther类里,可以像下面这样查询并设置结构体中的段位:
// set flag
_delegateFlaggs.didReceiveData = 1;
if (_delegateFlags.didReceiveData) {
// Yes,flag set
}
实现缓存功能所用的代码可以写在delegate属性对应的设置方法里:
- (void) setDelegate:(id<NetworkFetcherDelegate>delegate) {
_delegate = delegate;
_delegateFlags.didReceiveData = [delegate respondsToSelector:@selector(networkFetcher:didReceiveData:)];
...
}
这样的话,每次调用delegate的相关方法之前就不用检测委托对象是否能响应给定的选择子了,而是直接查询结构体里的标志:
if (_delegateFlags.didUpdateProgressTo) {
[_delegate networkFetcher:self didUpdateProgressTo:currentProgress];
}
在相关方法要调用很多次时,指的进行这种优化。
15.Category执行顺序
编译顺序
load顺序 编译顺序 load顺序
load执行顺序是先执行本类的,再执行分类的,分类的执行顺序由Compile Sources中文件编译顺序决定的,在上面的文件先编译,下面的文件后编译。
本类和分类有同名方法的,优先调用编译顺序在后面的分类中的方法。
category的方法被放到了新方法列表的前面,而原来类的方法被放到了新方法列表的后面,这也就是我们平常所说的category的方法会“覆盖”掉原来类的同名方法,这是因为运行时在查找方法的时候是顺着方法列表的顺序查找的,它只要一找到对应名字的方法,就会罢休。
16.锁和主线程
锁和主线程
17.@protocol中定义@property
默认没有set/get方法,在遵守协议的类中直接调用.xxx会挂的,写一个@syncthesize让编译器帮你实现set/get方法,或者自己定义一个成语变量,手动实现set/get方法。
//MyProtocal.h
@class NSString;
@protocol MyProtocal <NSObject>
@optional
@property (nonatomic, copy) NSString *name;
@end
//xxObject.h
#import "xxObject.h"
@interface TWPersion : NSObject<MyProtocal>
@end
//xxObject.m
#import "MyProtocal.h"
@implementation xxObject
@synthesize name = _name;
- (NSString*)description{
return [NSString stringWithFormat:@"%@",self.name];
// return [NSString stringWithFormat:@"%@",_name];
}
- (void)viewDidLoad {
[super viewDidLoad];
xxObject *obj = [[xxObject alloc] init];
obj.name = @"wang";
NSLog(@"%@",obj.description);
}
输出结果
网友评论