iOS - OC <<编写高质量iOS与OS X代码的多个有效方
Objective-C语言有Smalltalk演化而来,是消息型语言.
//Messaging (Objective-C)
Object *obj = [Object new];
[obj performWith:paramter1 and: paramter2];
//Function calling (C++)
Object *obj = new Object;
obj->perform(paramter1, paramter2);
区别
消息结构语言: 其运行时所执行的代码由运行环境决定.
函数调用语言: 由编译器决定.
调用多态:
1.函数通过虚方法表(virtual table)查找,到底该实行哪个函数;
2.消息结构语言是在运行时才会查找所需执行的方法,这个过程叫动态绑定(dynamic binding),Objective-C 都是由运行期组建(runtime component)来完成的.
1.在类的头文件中尽量少引入其他头文件
这样做的好处就是,能够缩短编译时间,所以当你引入一个类,而不需要知道这个类的细节(比如:用到这个类的某些属性/方法),只是声明它,则只需@class PersonClass
2.尽量多使用字面量语法,少用与之等价的方法
NSArray *tmpArr = @[@1,@2,@"funking hard"];
NSString *testStr = @"this is it";
NSDictionary *tmpDic = @{
@"last name" : @"Steve",
@"hobtis" : @"see around",
@"purpose" : @"making money"
};
这样的好处是一目了然,
3.多用类型常量,少用#define 预处理指令
static const NSTimeInterval kAnimationDuration = 0.3;
3.1 >这样定义会确保常量值不变,不会无意中被人修改,从而导致应用程序各个部分所使用的值互不相同,因为试图修改都会编译器报错.
3.2 >常量的命名习惯,建议以k字母开头,用类名区分,后面紧接着使用说明,比如kPersonClassAnimationDuration
,就能很清楚的知道这是所属于PersonClass这个类,用作动画时长的常量
3.3 >这样定义还可以标识类型,具有更多的参数信息.
3.4> 如果你想对外界暴露一个常值变量,又不想他知道具体的字符串,可以这样
//In the header file
extern NSString *const kEOCNotificationConstant;
//In the implementation file
NSString *const kEOCNotificationConstant = @"kEOCNotificationConstant";
4.用枚举表示状态,选项,状态码
enum EOCConnectionStateConnettionState : NSInteger {
EOCConnectionStateConnettionState_before,
EOCConnectionStateConnettionState_replace,
EOCConnectionStateConnettionState_after
};
你可以指定用什么类型存储该枚举类型,这样系统能更好的分配空间(默认系统的值是从 0 开始分配,)
typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
UIViewAutoresizingNone = 0,
UIViewAutoresizingFlexibleLeftMargin = 1 << 0,
UIViewAutoresizingFlexibleWidth = 1 << 1,
UIViewAutoresizingFlexibleRightMargin = 1 << 2,
UIViewAutoresizingFlexibleTopMargin = 1 << 3,
UIViewAutoresizingFlexibleHeight = 1 << 4,
UIViewAutoresizingFlexibleBottomMargin = 1 << 5
};
这种枚举类型就可以进行 "或" 运算,
如果需要按位或操作来组合的枚举都应该使用
NS_OPTIONS
来定义
不需要按位或 则 用enum
,NS_ENUM
,(因为编译分为C++和非C++编译,底层会做判断,是否支持新枚举特性,即指派存储类型,所以在定义上会有差别)
枚举使用:
如果你指定了一个可选类型 NSComparisonResult,则前面要加上 typedef
typedef NS_ENUM(NSInteger, NSComparisonResult) {
...
};
如果没有,就应该这样写...
NS_ENUM(NSInteger) {
...
};
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
switch (orientation) {
case UIInterfaceOrientationUnknown:
{
NSLog(@"位置状态");
}
break;
case UIInterfaceOrientationPortrait:
{
NSLog(@"竖屏状态");
}
break;
case UIInterfaceOrientationPortraitUpsideDown:
{
NSLog(@"倒竖屏状态");
}
break;
case UIInterfaceOrientationLandscapeLeft:
case UIInterfaceOrientationLandscapeRight:
{
NSLog(@"左右状态");
}
break;
//default:
//break;
}
在处理枚举类型的switch语句中,不要实现default分支,这样的话加入新枚举之后,编译器就会提示开发者:switch语句并未处理所有枚举
5. 属性的一些细节
应用程序二进制接口 (Application Binary Interface ABI),其中定义了生成代码时所赢遵循的规范.
图1
这是我看到所有对属性解释中,最清晰简洁的
//In header file
@property (copy) NSString *firstName;
@property (copy) NSString *lastName;
//In implementation file
- (id) initWithFirstName:(NSString *)firstName
lastName:(NSString *)lastName;
{
if ((self = [super init])) {
_firstName = [firstName copy];
_lastName = [lastName copy];
}
return self;
}
iOS开发相比于 Mac OS X开发,使用atomic
通常不会有性能瓶颈.
在初始化方法 和 dealloc 中直接通过实例变量(_firstName)来获取;
内部对象读取时,直接_firstName
,写入数据时,通过属性set赋值self.firstName = @"XXX"
6. 理解 "对象等同性" 这一概念
NSString *foo = @"test 123";
NSString *bar = [NSString stringWithFormat:@"test %i",123];
BOOL equalA = (foo == bar); 对比的是对象地址
BOOL equalB = [foo isEqual:bar];判断两个对象的地址是否相同,再判断类型是否一致, 然后再判断对象的具体内容是否一致
BOOL equalC = [foo isEqualToString:bar]; 首先两个对象必须为NSString类型,其次得相等.
NSLog(@"equalA:%zd equalB: %zd equalC: %zd",equalA,equalB,equalC);
//equalA:0 equalB: 1 equalC: 1
自定义判定等同性方法
//In header file
@interface ECOPerson : NSObject
@property(nonatomic,copy)NSString *firstName;
@property(nonatomic,copy)NSString *lastName;
@property(assign,nonatomic) NSUInteger age;
@end
//In implementation
- (BOOL)isEqual:(id)object
{
if (self.class == [object class]) {
return [self isEqualToPerson:object];
} else {
return [super isEqual:object];
}
}
- (BOOL)isEqualToPerson:(ECOPerson *)otherPerson
{
if (self == otherPerson) {
return YES;
}
if (self.class != [otherPerson class]) {
return NO;
}
if (![otherPerson.firstName isEqualToString:self.firstName]) {
return NO;
}
if (![otherPerson.lastName isEqualToString:self.lastName]) {
return NO;
}
if (otherPerson.age != self.age) {
return NO;
}
return YES;
}
- (NSUInteger)hash
{
NSUInteger fistNameHash = [_firstName hash];
NSUInteger lastNameHash = [_lastName hash];
NSUInteger ageHash = _age;
return fistNameHash ^ lastNameHash ^ ageHash;
}
哈希值相等 不一定 两个对象相等,但两个对象相等,哈希值一定相等;
若想检测对象的等同性,请提供"isEqual" 与 "hash"方法
编写hash方法时,尽量使用计算速度快,哈希碰撞少的算法.