effective objective-c 41条,是否有误
1个回答
展开全部
1.除非有必要,否则不要引用头文件,一般来说应该利用@class使用前向声明,并在实现中引用头文件;如果实在无法使用,比如要声明某个类遵循一项协议,这种情况下,尽量把这条声明移到分类中,如果不行的话,就把协议单独放到一个头文件中,然后再引入
2.应该使用字面量语法来创建字符串、数值、数组、字典,这样做更加简明扼要;应该通过下标操作来访问数组或字典中的值;需要注意的是,采用字面量语法,若值有nil,会抛出异常。
3.不用使用预处理指令定义常量;在实现文件中用static const来定义内部常量(以k开通),这样就不会出现在全局符号表中;在头文件中使用extern来声明全局常量,并在相关实现文件中定义其值,他会出现在全局符号表,所以其名称应加以区别,通常用与之相关的类名做前缀
4.用NS_ENUM与NS_OPTIONS宏来定义枚举类型,并指明其底层数据类型,确保枚举类型底层数据类型的可控性; 其语法为:
typedef NS_ENUM(NSUInteger,xxx){};
typedef NS_OPTIONS(NSInteger,YYY){};
5.可以用@property语法来定义对象中所封装的数据,并通过atomic/nonatomic/readwrite/readonly/assign/unsafe_unretained/strong/weak/copy等特性来指定存储数据所需的正确定义,还可以在声明@property的时候利用getter=<name>和setter=<name>来指定其相应的方法名;并且在设置属性所对应的实例变量时,一定要遵从该属性所声明的语义
6.在对象内部读取数据时,应该直接通过实例变量来读,而写入数据时,则应通过属性来写;在初始化及dealloc方法中,应该通过实例变量来读取数据,防止子类因为对属性方法的重载导致的问题;如果使用惰性初始化技术的数据,必须通过属性来读取数据
7.若要想检测对象的等同性,请提供isEqual与hash方法,对于内置对象,已经提供了isEqualToArray/isEqualToDictionary/isEqualToString方法;并且要清楚hash相等只是一个必要而非充分的条件;不要盲目地逐个检测每条属性,而是应该按照具体需求来制定检测方案
8.所谓的类族就是把实现细节隐藏在一套简单的公共接口里面,基类实现类方法;系统框架中经常使用类族,所在要小心的是你所想要的类也许是该类的子类,故就不能用isMemberOfClass或==来做判断,而应该采用isKindOfClass来做判断
9.所谓关联对象就是把对象当成NSDictionary来存储key-value,类似给对象设置动态属性,用方法:objc_setAssociatedObject /objc_getAssociatedObject /objc_removeAssociatedObject全句方法来完成设置/获取/删除;他有相应的关联类型:
OBJC_ASSOCIATION_ASSIGN
OBJC_ASSOCIATION_RETAIN_NONATOMIC
OBJC_ASSOCIATION_COPY_NONATOMIC
OBJC_ASSOCIATION_RETAIN
OBJC_ASSOCIATION_COPY
想要注意的是,只有在其他做法不可行时才应选用关联对象,因为这种做法通常会引入难于查找的BUG,一般都可以继承实现子类的方法来解决
10.利用objc_msgSend/objc_msgSend_stret/objc_msgSend_fpret/objc_msgSendSuper来实现动态消息派发系统,当给某对象发送消息时,该系统会查出对应的方法,在该对象上调用其C代码
11.消息转发流程包含三个部分:resolveInstanceMethod->forwardingTargetForSelector->forwardInvocation,对应第一步可以实现对@dynamic属性的设置,第二步可以实现类似多继承的方式,第三步会封装NSInvocation对象,进行完整的消息派发流程;故步骤越往后,处理消息的代价越大,如果第一步处理完,就可以缓存,后续访问直接就可以返回而不需要启动消息转发流程,第二步可以以组合的方式来实现多继承,第三步由于要创建NSInvocation对象,消耗最大;需要用到辅助函数NSStringFromSelector来将方法名转成字符串,另外,利用class_addMethod来动态添加成员方法
12.利用方法调配技术,并结合class_getInstaneMethod和method_exchangeImplementations函数可以向类中新增或替换选择子所对应的方法实现,或者使用另一份实现来替换原有的;但是,只有调试程序的时候才需要在运行期修改方法实现,这种做法不宜滥用;需要注意的事,要包含<objc/runtime.h>头文件
13.每个实例都有一个指向Class对象的指针,而Class对象又有一个指向MetaClass的指针,并且每个对象都有相应的super来指向自己相应的基类,这样就构成了类的继承体系;如果对象类型无法在编译器确定,那么就应该使用类型信息查询方法来探知,而不要直接比较类对象,因为某些对象可能实现了消息转发功能
14.Apple宣称其保留使用所有"两字母前缀"的权利,故应选择与你的公司、应用程序或二者皆有关联之名作为类名的前缀,并在所有的代码中均使用这一前缀;若自己所开发的程序中用到了第三方库,则应为其中的名称加上前缀
15.在类中提供一个全能初始化方法,其他初始化方法均应调用此方法;若全能初始化方法与超类不同,则覆写超类中对应的方法;如果超类的初始化方法不使用子类,那么覆写这个超类方法,并在其中抛出异常(类方法NSException exceptionWithName)
16.如果想要@%打印出自定义的对象,需要实现其description方法返回一个有意义的字符串;若想在调试时利用po命令打印出更详尽的对象描述信息,则应实现debugDescription方法;需要注意的是,可以把待打印的信息放到字典里面(字面量语法),然后将字典对象的description方法所输出的内容包含在字符串里并返回,实现精简的信息输出方式
17.尽量创建不可变的对象,若某属性仅可于对象内部修改,则在分类中将其由readonly属性扩展为readwrite属性;并且不要把可变的collection作为属性公开,而应该提供相关的方法,以此修改对象中的可变collection
18.给私有方法的名称加上前缀,这样可以很容易地将其同公共方法区分开;并且不要单用一个下划线做私有方法的前缀,因为这种做法是预留给Apple公司使用的;需要注意的是,与公共方法不同,私有方法不出现在接口定义中,一般只在实现的时候声明,因为Objective-C中没有那种约束方式调用的机制用以限定谁能调用此方法、能在哪个对象上调用此方法以及何时能调用此方法
19.Objective-C只在极其罕见的情况下抛出异常,抛出以后就无须考虑恢复问题,而且应用程序此时也应该退出,也就是说,不同再编写复杂的"异常安全"代码了;那么对于不是非致命的错误,可以令方法返回nil/0,或使用NSError,以表明其中有错误发生;使用后者更加灵活,该对象封装了三条信息:Error domain(错误范围,类型为字符串)/Error code(错误吗,类型为整数)/User info(用户信息,类型为字典),可以把他以Delegate或输出参数的方式返回给使用者
20.要实现NSCopying协议,就是要实现方法 {-(id) copyWithZone:(NSZone*)zone};要实现NSMutableCopying协议,就是要实现方法 {-(id) mutableCopyWithZone:(NSZone*)zone};在函数中,可以这样写:XXX* copy = [[[self class] allocWithZone:zone] initXXX:YYY];需要注意的是,Foundation框架中的所有colletion类在默认情况下都执行浅拷贝,所有我们会遵照系统框架所使用的模式,在自定义的类中以浅拷贝的方式实现copyWithZone,如果真的要深拷贝,则另外单独起一个新方法;对了在Objective-C中,也是使用->语法,这样他就是直接访问变量,不再走属性那一套了
2.应该使用字面量语法来创建字符串、数值、数组、字典,这样做更加简明扼要;应该通过下标操作来访问数组或字典中的值;需要注意的是,采用字面量语法,若值有nil,会抛出异常。
3.不用使用预处理指令定义常量;在实现文件中用static const来定义内部常量(以k开通),这样就不会出现在全局符号表中;在头文件中使用extern来声明全局常量,并在相关实现文件中定义其值,他会出现在全局符号表,所以其名称应加以区别,通常用与之相关的类名做前缀
4.用NS_ENUM与NS_OPTIONS宏来定义枚举类型,并指明其底层数据类型,确保枚举类型底层数据类型的可控性; 其语法为:
typedef NS_ENUM(NSUInteger,xxx){};
typedef NS_OPTIONS(NSInteger,YYY){};
5.可以用@property语法来定义对象中所封装的数据,并通过atomic/nonatomic/readwrite/readonly/assign/unsafe_unretained/strong/weak/copy等特性来指定存储数据所需的正确定义,还可以在声明@property的时候利用getter=<name>和setter=<name>来指定其相应的方法名;并且在设置属性所对应的实例变量时,一定要遵从该属性所声明的语义
6.在对象内部读取数据时,应该直接通过实例变量来读,而写入数据时,则应通过属性来写;在初始化及dealloc方法中,应该通过实例变量来读取数据,防止子类因为对属性方法的重载导致的问题;如果使用惰性初始化技术的数据,必须通过属性来读取数据
7.若要想检测对象的等同性,请提供isEqual与hash方法,对于内置对象,已经提供了isEqualToArray/isEqualToDictionary/isEqualToString方法;并且要清楚hash相等只是一个必要而非充分的条件;不要盲目地逐个检测每条属性,而是应该按照具体需求来制定检测方案
8.所谓的类族就是把实现细节隐藏在一套简单的公共接口里面,基类实现类方法;系统框架中经常使用类族,所在要小心的是你所想要的类也许是该类的子类,故就不能用isMemberOfClass或==来做判断,而应该采用isKindOfClass来做判断
9.所谓关联对象就是把对象当成NSDictionary来存储key-value,类似给对象设置动态属性,用方法:objc_setAssociatedObject /objc_getAssociatedObject /objc_removeAssociatedObject全句方法来完成设置/获取/删除;他有相应的关联类型:
OBJC_ASSOCIATION_ASSIGN
OBJC_ASSOCIATION_RETAIN_NONATOMIC
OBJC_ASSOCIATION_COPY_NONATOMIC
OBJC_ASSOCIATION_RETAIN
OBJC_ASSOCIATION_COPY
想要注意的是,只有在其他做法不可行时才应选用关联对象,因为这种做法通常会引入难于查找的BUG,一般都可以继承实现子类的方法来解决
10.利用objc_msgSend/objc_msgSend_stret/objc_msgSend_fpret/objc_msgSendSuper来实现动态消息派发系统,当给某对象发送消息时,该系统会查出对应的方法,在该对象上调用其C代码
11.消息转发流程包含三个部分:resolveInstanceMethod->forwardingTargetForSelector->forwardInvocation,对应第一步可以实现对@dynamic属性的设置,第二步可以实现类似多继承的方式,第三步会封装NSInvocation对象,进行完整的消息派发流程;故步骤越往后,处理消息的代价越大,如果第一步处理完,就可以缓存,后续访问直接就可以返回而不需要启动消息转发流程,第二步可以以组合的方式来实现多继承,第三步由于要创建NSInvocation对象,消耗最大;需要用到辅助函数NSStringFromSelector来将方法名转成字符串,另外,利用class_addMethod来动态添加成员方法
12.利用方法调配技术,并结合class_getInstaneMethod和method_exchangeImplementations函数可以向类中新增或替换选择子所对应的方法实现,或者使用另一份实现来替换原有的;但是,只有调试程序的时候才需要在运行期修改方法实现,这种做法不宜滥用;需要注意的事,要包含<objc/runtime.h>头文件
13.每个实例都有一个指向Class对象的指针,而Class对象又有一个指向MetaClass的指针,并且每个对象都有相应的super来指向自己相应的基类,这样就构成了类的继承体系;如果对象类型无法在编译器确定,那么就应该使用类型信息查询方法来探知,而不要直接比较类对象,因为某些对象可能实现了消息转发功能
14.Apple宣称其保留使用所有"两字母前缀"的权利,故应选择与你的公司、应用程序或二者皆有关联之名作为类名的前缀,并在所有的代码中均使用这一前缀;若自己所开发的程序中用到了第三方库,则应为其中的名称加上前缀
15.在类中提供一个全能初始化方法,其他初始化方法均应调用此方法;若全能初始化方法与超类不同,则覆写超类中对应的方法;如果超类的初始化方法不使用子类,那么覆写这个超类方法,并在其中抛出异常(类方法NSException exceptionWithName)
16.如果想要@%打印出自定义的对象,需要实现其description方法返回一个有意义的字符串;若想在调试时利用po命令打印出更详尽的对象描述信息,则应实现debugDescription方法;需要注意的是,可以把待打印的信息放到字典里面(字面量语法),然后将字典对象的description方法所输出的内容包含在字符串里并返回,实现精简的信息输出方式
17.尽量创建不可变的对象,若某属性仅可于对象内部修改,则在分类中将其由readonly属性扩展为readwrite属性;并且不要把可变的collection作为属性公开,而应该提供相关的方法,以此修改对象中的可变collection
18.给私有方法的名称加上前缀,这样可以很容易地将其同公共方法区分开;并且不要单用一个下划线做私有方法的前缀,因为这种做法是预留给Apple公司使用的;需要注意的是,与公共方法不同,私有方法不出现在接口定义中,一般只在实现的时候声明,因为Objective-C中没有那种约束方式调用的机制用以限定谁能调用此方法、能在哪个对象上调用此方法以及何时能调用此方法
19.Objective-C只在极其罕见的情况下抛出异常,抛出以后就无须考虑恢复问题,而且应用程序此时也应该退出,也就是说,不同再编写复杂的"异常安全"代码了;那么对于不是非致命的错误,可以令方法返回nil/0,或使用NSError,以表明其中有错误发生;使用后者更加灵活,该对象封装了三条信息:Error domain(错误范围,类型为字符串)/Error code(错误吗,类型为整数)/User info(用户信息,类型为字典),可以把他以Delegate或输出参数的方式返回给使用者
20.要实现NSCopying协议,就是要实现方法 {-(id) copyWithZone:(NSZone*)zone};要实现NSMutableCopying协议,就是要实现方法 {-(id) mutableCopyWithZone:(NSZone*)zone};在函数中,可以这样写:XXX* copy = [[[self class] allocWithZone:zone] initXXX:YYY];需要注意的是,Foundation框架中的所有colletion类在默认情况下都执行浅拷贝,所有我们会遵照系统框架所使用的模式,在自定义的类中以浅拷贝的方式实现copyWithZone,如果真的要深拷贝,则另外单独起一个新方法;对了在Objective-C中,也是使用->语法,这样他就是直接访问变量,不再走属性那一套了
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询