目录


1 Object Hierarchy & Messaging

Item 6:Understand Properties

  1. @property = _iVar + setter + getter。To prevent @property automatically create _iVar + setter + getter,use @dynamic;To customize your own iVar’s name (not _iVar),use @synthesis。

  2. @property attribues:atomicity(nonatomic,atomic),read/write(readwrite,readonly),memeory-management(assing,strong,weak,copy),method name(getter,setter)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
//  EOCCat.h
#import <Foundation/Foundation.h>

@interface EOCCat : NSObject
@property(nonatomic,strong) NSString *name0;
@property(nonatomic,strong) NSString *name1;
@property(nonatomic,strong) NSString *name2;

@property(nonatomic,strong,readonly) NSString *nameReadOnly;
@property(nonatomic,copy) NSString *nameCopy;
@property(nonatomic,assign,getter=isMale)BOOL male;
-(instancetype)initWithNameCopy:(NSString *)nameCopy;
-(void)changeNameCopy:(NSString *)nameCopy;
@end


//  EOCCat.m
#import "EOCCat.h"

@interface EOCCat()
@property(nonatomic, strong, readwrite) NSString *nameReadOnly;
@end

@implementation EOCCat
@synthesize name1 =_myName1;
@dynamic name2;

-(instancetype)initWithNameCopy:(NSString *)nameCopy{
    if(self = [super init]){
        _name0 = @"name0";
        _myName1 = @"myName1";
        //_name2 error, since dynamic forbidden its _iVar+setter+getter auto create
        //in init, one cannot use setter, thus [nameCopy copy] is used to conform to _nameCopy's copy attributes
        _nameCopy = [nameCopy copy];
        _nameReadOnly = @"readOnly1";
    }
    return self;
}

-(void)changeNameCopy:(NSString *)nameCopy{
    //nameCopy will be copied to self.nameCopy
    self.nameCopy = nameCopy;
    //self.nameReadOnly can only be changed once it redeclared as readwrite in .m
    self.nameReadOnly = @"readOnyly2";
}

Item 7:Access Instance Variables Primarily Directly When Accessing Them Internally

  1. For external access,property usage is without doubt。

  2. For internal access,use property except in init,setter,getter,dealloc。 Since property encapsulate setter(customization),getter(lazy instantiate), memory-managment(_iVar = someValue not retain new value and release old value while self.iVar do) and copy (_iVar = someValue don’t copy it while self.iVar = someValue do if @property with copy)。

Item 8:Understand Object Equality

  1. Object euqality必须实现下面两个方法:用 isEuqal(用于两者比较);hash用于collection内object的比较,例如set。前者相同的后者必须相同,后者相同的前者不用相同。两者都属于NSObject协议。

  2. 对于创建的Class,可以写isEqualToClass方法,例如NSStringisEqualToStringNSArrayisEuqalToArrayNSDictionaryisEuqalToDictionary。可以用isEqualToClass(不需要check类是否相同)来实现isEqual方法(需要check类是否相同,不同返回false)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
-(BOOL)isEqualToPerson:(EOCPerson *)other{
    if(self == other) return YES; //if points to the same instance, return YES
    
    if(![self.firstName isEqualToString:other.firstName]){
        return NO;
    }
    if(![self.lastName isEqualToString:other.lastName]){
        return NO;
    }
    return YES;
}

-(BOOL)isEqual:(id)object{
    if([object isKindOfClass:[self class]]){
        return [self isEqualToPerson:object];
    }else{
        return [super isEqual:object];
    }
}

-(NSUInteger)hash{
    return [self.firstName hash]^[self.lastName hash];
}

Item 9:Use the Class Cluster Pattern to Hide Implementation Detail

  1. 类簇可以减少类的种类,子类信息被类簇隐藏,调用者不需要知道子类。比如NSSnumber是一个类簇,如果不使用类簇的话,需要为每一种基本类型都提供一种封装,这样会使类的数量极其庞大,程序员需要记住大量的类,但是如果使用类簇的话,只需要记住NSNumber这一个类就行了,具体使用这个类返回的是什么类型的对象,会在NSNumber类内部做处理和判断,而不需要调用者来关心,调用者只需要知道NSNumber的接口拿来用即可。

  2. Subclass abstract class在类簇里和Subclass normal class是完全不一样的。后者可以是一个空的实现,因为super class已经提供了完整实现;而前者需要实现super class接口的函数,因为这部分在super class里只是一个空壳。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
//EOCMployee.h
#import <Foundation/Foundation.h>

typedef NS_ENUM(NSUInteger,EOCEmployeeType){
    EOCEmployeeTypeDeveloper,
    EOCEmployeeTypeDesigner,
    EOCEmployeeTypeFinance,
};

@interface EOCEmployee : NSObject
+(EOCEmployee *)employeeWithType:(EOCEmployeeType)type;
-(void)doWork;
@end



//EOCEmployee.m
#import "EOCEmployee.h"

@interface EOCEmployeeDeveloper : EOCEmployee
@end
@implementation EOCEmployeeDeveloper
-(void)doWork{
    NSLog(@"%@,%@",[self class],NSStringFromSelector(_cmd));
}
@end

@interface EOCEmployeeDesigner : EOCEmployee
@end
@implementation EOCEmployeeDesigner
-(void)doWork{
    NSLog(@"%@,%@",[self class],NSStringFromSelector(_cmd));
}
@end

@interface EOCEmployeeFinance : EOCEmployee
@end
@implementation EOCEmployeeFinance
-(void)doWork{
    NSLog(@"%@,%@",[self class],NSStringFromSelector(_cmd));
}
@end

@interface EOCEmployee()
@property(nonatomic,assign)EOCEmployeeType type;
@end

@implementation EOCEmployee

+(EOCEmployee *)employeeWithType:(EOCEmployeeType)type{
    EOCEmployee *employee;
    switch (type) {
        case EOCEmployeeTypeDeveloper:
            employee = [EOCEmployeeDeveloper new];
            break;
        case EOCEmployeeTypeDesigner:
            employee = [EOCEmployeeDesigner new];
            
        case EOCEmployeeTypeFinance:
            employee = [EOCEmployeeFinance new];
    }
    employee.type = type;
    return employee;
}

-(void)doWork{
    //Subclass implement this.
    //Without class cluster, you need to implement with lots of cumbersome if/else
    if(self.type == EOCEmployeeTypeDeveloper){
        //do developer work
    }else if (self.type == EOCEmployeeTypeDesigner){
        //do designer work
    }else if (self.type == EOCEmployeeTypeFinance){
        //do finance work
    }
}
@end

Item 10:Use Associated Objects to Attach Custom Data to Existing Classes

1.对已有的类进行实例变量扩展可以通过category结合runtime实现,具体有3个方法:objc_setAssociatedObject(id object, void *key, id value, objc_AssociationPolicy policy)objc_getAssociatedObject(id object, void *key)void objc_removeAssociatedObjects(id object)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//EOCPerson+ID.h
#import "EOCPerson.h"

@interface EOCPerson (ID)
@property(nonatomic, strong) NSString *id;
@end

//EOCPerson+ID.m
#import "EOCPerson+ID.h"
#import <objc/runtime.h>
@implementation EOCPerson (ID)

-(void)setId:(NSString *)id{
    objc_setAssociatedObject(self,@selector(id),id,OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

-(NSString *)id{
    return objc_getAssociatedObject(self,@selector(id));
}
@end

Item 11:Understand the Role of objc_msgSend

OC Runtime(零):Runtime概述OC Runtime(二):Messaging Part I:消息机制和swizzling

Item 12:Understand Message Forwarding

OC Runtime(零):Runtime概述OC Runtime(二):Messaging Part I:消息机制和swizzling

Item 13:Consider Method Swizzling to Debug Opaque Methods

OC Runtime(零):Runtime概述OC Runtime(二):Messaging Part I:消息机制和swizzling

Item 14:Understand What a Class Object Is

OC Runtime(零):Runtime概述OC Runtime(一):Object Model Part I:Object Hierarchy

2 Reference


Share Post

Twitter Google+

Shunmian

The only programmers in a position to see all the differences in power between the various languages are those who understand the most powerful one.