读EffectiveObjective-C2.0(第一条、第二条)

读EffectiveObjective-C2.0(第一条、第二条)

IOS小彩虹2021-07-14 14:45:1690A+A-

第一条:了解Objective-C语言的起源

  • Objective-C使用消息结构。消息结构的语言,其运行时所应执行的代码由运行环境决定;而使用函数调用的语言,则由编译器决定。Objective-C是一门动态的语言。
  • Objective-C对象的内存管理使用的是引用计数机制。

第二条:在类的头文件中尽量少引用其他头文件

  • 用Objective-C语言编写类的标准方式为:以类作为文件名,分别创建两个文件,头文件用后缀.h实现文件用后缀.m
// EOCPerson.h
#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface EOCPerson : NSObject
@property (nonatomic, copy) NSString *firstName;
@property (nonatomic, copy) NSString *lastName;
@end

NS_ASSUME_NONNULL_END
  
// EOCPerson.m
#import "EOCPerson.h"
@implementation EOCPerson

@end
  • 假设,过段时间,我们可能需要一个新的类EOCEmployer,并且每个EOCPerson实例都会有一个EOCEmployer属性。此时我们需要在EOCPerson的头文件中,定义一个EOCEmployer属性。
// EOCPerson.h
#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface EOCPerson : NSObject
@property (nonatomic, copy) NSString *firstName;
@property (nonatomic, copy) NSString *lastName;
@property (nonatomic, strong) EOCEmployer *employer;
@end

NS_ASSUME_NONNULL_END
  • 此时,编译器会报错,原因是找不到EOCEmployer类,那么我们可以通过引入EOCEmployer的头文件来解决这个报错。
#import "EOCEmployer.h"
  • 这种办法成功解决了编译器的报错,但是不够优雅,原因是:在编译EOCPerson类的时候,不需要知道EOCEmployer的全部细节,只需要知道有一个类名叫EOCEmployer就好了。
  • 我们可以使用向前声明,告诉编译器有EOCEmployer这个类,而不需要去引入EOCEmployer的全部内容。格式为:@class 类名;
// EOCPerson.h
#import <Foundation/Foundation.h>
@class EOCEmployer;

NS_ASSUME_NONNULL_BEGIN

@interface EOCPerson : NSObject
@property (nonatomic, copy) NSString *firstName;
@property (nonatomic, copy) NSString *lastName;
@property (nonatomic, strong) EOCEmployer *employer;
@end

NS_ASSUME_NONNULL_END
  • 那么,在什么时候才需要真正引入EOCEmployer的头文件呢?在EOCPerson的实现文件中,真正需要使用EOCEmployer的时候。我们就必须要知道EOCEmployer的全部细节了。
// EOCPerson.m
#import "EOCPerson.h"
#import "EOCEmployer.h"

@implementation EOCPerson
- (void)setEmployer:(EOCEmployer *)employer {
    _employer = employer;
    _firstName = employer.nickName;
}
@end

将引入头文件的时机尽量延后,在确实需要使用的时候引入,这样可以减少类的使用者所需引入头文件的数量。假设把EOCEmployer.h的头文件引入到EOCPerson.h,那么其他文件引入EOCPerson.h就会一并引入EOCEmployer.h的全部内容,而其他文件不需要用到EOCEmployer.h中的内容,这么延续下去的话,会引入许多额外的没有用的头文件,就会增加编译时间。

  • 向前声明还可以解决两个类相互引用的问题。假设为EOCEmployer类加入新增及删除雇员的方法。此时需要我们引入EOCPerson类,否则找不到EOCPerson类。
- (void)addEmployee:(EOCPerson *)person;
- (void)removeEmployee:(EOCPerson *)person;
  • 如果我们在EOCPerson的头文件中引入EOCEmployer的头文件,并且在EOCEmployer头文件中引入EOCPerson的头文件,此时就会产生循环引用的问题。此时编译器会报错。使用向前声明即可解决这样的问题。

  • 有些时候必须在头文件中引入其他头文件。不能使用向前声明。

    • 如果你写的类,继承自某个父类,则必须引入父类的头文件
    // EOCRectangle.h
    #import "EOCShape.h"
      
    NS_ASSUME_NONNULL_BEGIN
      
    @interface EOCRectangle : EOCShape
    @property (nonatomic, assign) CGFloat width;
    @property (nonatomic, assign) CGFloat height;
    @end
      
    NS_ASSUME_NONNULL_END
    
    • 如果你写的类,遵守某个协议,那么该协议必须有完整的定义,不能使用向前声明。
    #import "EOCShape.h"
    #import "EOCDrawable.h"
      
    NS_ASSUME_NONNULL_BEGIN
      
    @interface EOCRectangle : EOCShape <EOCDrawable>
    @property (nonatomic, assign) CGFloat width;
    @property (nonatomic, assign) CGFloat height;
    @end
      
    NS_ASSUME_NONNULL_END
    
  • 协议最好放在一个单独文件里进行定义,如果把EOCDrawable协议写在了某个大的头文件中,只要引入协议,还会额外引入大的头文件中的全部内容,这样就会产生相互依赖,而且会增加编译时间。

  • 如果是委托协议,就不用单独写一个文件里了,委托协议只有和接收委托协议的类放在一起才有意义,在类的实现文件中实现委托协议就可以了。

点击这里复制本文地址 以上内容由权冠洲的博客整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!

支持Ctrl+Enter提交

联系我们| 本站介绍| 留言建议 | 交换友链 | 域名展示
本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除

权冠洲的博客 © All Rights Reserved.  Copyright quanguanzhou.top All Rights Reserved
苏公网安备 32030302000848号   苏ICP备20033101号-1

联系我们