Happy iOS

Effective OC

2016-01-14  本文已影响76人  tongxyj

1.OC为C语言添加了面向对象特性,是其超集。OC使用动态绑定的消息结构,也就是说,在运行时才会检查对象类型。接收一条消息后,究竟应执行何种代码,由运行期环境而非编译器决定。
2.在类的头文件中尽量少引用其他头文件

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.在对象内部读取数据时,应该直接通过实例变量来读,而写入数据时,则应通过属性来写。

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);
}
输出结果
上一篇 下一篇

猜你喜欢

热点阅读