Stay weird. Stay different.

0%

Effective Objective-c 2.0读书笔记(五)

  • 第十六条:提供“全能初始化方法”

    一个类中可能有多个初始化方法,但是在设计中需要制定其中一个方法为全能初始化方法,每个初始化方法都需要先调用这个全能初始化方法。

    例如有这样一个类:EOCRectangle

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @interface EOCRectangle: NSObject

    @property (nonatomic, assign, readonly) CGFloat width;
    @property (nonatomic, assign, readonly) CGFloat height;

    - (instancetype) initWithWidth:(CGFloat)width
    andHeight:(CGFloat)height;

    @end

    一下是我们定义的全能初始化方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    - (instancetype) initWithWidth:(CGFloat)width
    andHeight:(CGFloat)height{
    self = [super init];
    if(self){
    _width = width;
    _height = height;
    }
    return self;
    }

    再定义一个类EOCSquare 继承自EOCRectangle

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #import "EOCRectangle.h"

    @interface EOCSquare : EOCRectangle

    - (instancetype) initWithDimension:(CGFloat)dimension;

    @end

    #implementation EOCSquare

    - (instancetype) initWithDimension:(CGFloat)dimension {
    return [self initWithWidth:dimension andHeight:dimension];
    }

    由于EOCSquare可以调用父类的方法,有可能出现无意中调用了- (instancetype) initWithWidth:(CGFloat)width andHeight:(CGFloat)height这个方法,造成 生成的EOCSquare对象的不是一个正方形,可以采用下面的这种方法覆写全能初始化方法

    1
    2
    3
    4
    5
    - (instancetype) initWithWidth:(CGFloat)width
    andHeight:(CGFloat)height{
    float dimension = MAX(width, height);
    return [self initWithDimension:dimension];
    }
  • 第十七条:实现description方法

    自定义类中,如果想要通过NSLog打印对象信息,则需要重写NSObject中的- (NSString *)description方法。如果是想通过调试器命令po打印对象信息则需要重写- (NSString *)debugDescription方法。

  • 第十八条:尽量使用不可变对象

    在类外部暴露的属性尽量设置成readonly属性,已防止用户进行没必要的修改。如果需要在类内部进行修改,可以通过分类的方式,在.m文件中重新定义相同名称的属性为readwrite,这样就可以在类内部的实现中进行修改。例如:

    1
    2
    3
    4
    5
    6
    @interface EOCPointOfInternet : NSObject

    @property (nonatomic, copy, readonly) NSString *identifier;
    @property (nonatomic, copy, readonly) NSString *title;

    @end
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    @import "EOCPointOfInternet.h"

    @interface EOCPointOfInternet ()

    @property (nonatomic, copy, readwrite) NSString *identifier;
    @property (nonatomic, copy, readwrite) NSString *title;

    @end

    @implementation EOCPointOfInternet

    @end

    但这样会产生另外一个问题,在类的外部仍然可以通过KVC的方式设置这些属性值,比如

    1
    pointOfInternet setValue:@"abc" forKey@"identifier"];

    这种方法是通过KVO的方式去类中查找setIdentifier方法,即便该类没有公布此方法也可以使用。但并不推荐使用

    还有如果属性中包含各种collection类型的属性,依然推荐采取不可变的形式,例如:

    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
    @interface EOCPerson : NSObject

    @property (nonatomic, strong, readonly) NSSet *friends

    - (void)addFriend:(EOCPerson *)person;
    - (void)removeFriend:(EOCPerson *)person;

    @end

    #import "EOCPerson.h"

    #implementation EOCPerson {
    NSMutableSet *_internalFriends;
    }

    - (NSSet *)friends {
    return [_internalFriends copy];
    }

    - (void)addFriend:(EOCPerson *)person {
    [_internalFriends addObject:person];
    }

    - (void)removeFriend:(EOCPerson *)person {
    [_internalFriends removeObject:person];
    }

    通过这种方式类的内部维护着一个可变的collection,而暴露出来的属性是不可变的。