第23条:通过委托与数据源协议进行对象间通信
在软件开发中,对象之间的通信是不可避免的。委托模式(Delegate Pattern)是一种常用的实现对象间通信的方式,也被称为代理模式。委托模式的核心思想是定义一套接口,使得一个对象可以将部分职责委托给另一个对象。在iOS开发中,常常通过委托模式实现数据的传递和事件的通知。
1. 委托模式概述
委托模式的主要步骤包括定义协议、声明委托属性、实现委托方法。需要注意的是,协议中的属性应该使用weak
修饰符,以避免循环引用问题。在.m文件中遵循协议,实现委托方法。
@protocol MyDelegate <NSObject>
- (void)didReceiveData:(NSData *)data;
- (void)didTriggerEvent;
@end
@interface MyClass : NSObject
@property (nonatomic, weak) id<MyDelegate> delegate;
@end
@implementation MyClass
// 实现类的相关逻辑,调用委托方法
@end
2. 委托的两种情况
委托模式通常分为两种情况:数据和类之间的委托(数据源模式)以及对象将行为责任委托给另一个类。
在实现委托和数据源模式时,可以使用C语言中的“位段”数据类型,通过缓存方法的响应能力,提高程序的运行效率。
// 使用位段缓存方法的响应能力
struct {
unsigned int respondsToMethod1:1;
unsigned int respondsToMethod2:1;
// ... 其他方法
} delegateFlags;
3. 要点
- 委托模式为对象提供一套接口,用于将相关事件告知其他对象。
- 将委托对象应该支持的接口定义成协议,并在协议中定义可能需要处理的事件。
- 数据源模式适用于对象需要从另一个对象中获取数据的情况。
第24条:将类的实现代码分散到便于管理的数个分类中
Objective-C中的分类机制不仅用于补充类的功能,还可以用于规划代码,将类的实现代码分成多个易于管理的小块。通过分类,可以提高代码的可读性和维护性。
使用分类规划代码
// Friendship.h
@interface MyClass (Friendship)
- (void)friendshipMethod;
@end
// Work.h
@interface MyClass (Work)
- (void)workMethod;
@end
// Play.h
@interface MyClass (Play)
- (void)playMethod;
@end
在实际使用中,通过引入相应的头文件,可以使代码结构更加清晰。
利用分类管理私有方法
可以将私有方法放入单独的分类中,并使用特殊的前缀表示它们是私有方法。这样一方面可以遵循命名规则,另一方面可以在调试时清晰地识别私有方法。
要点
- 使用分类机制把类的实现代码划分成易于管理的小块。
- 将应该视为“私有”的方法归入名叫Private的分类中,以隐藏实现细节。
第25条:总是为第三方的分类名称加前缀
在使用分类机制向第三方类中添加功能时,为了避免方法名的冲突和覆盖,应始终为分类的名称和方法名加上特定的前缀。
为分类名称和方法名加前缀
// MyCategory.h
@interface NSString (MyCategory)
- (NSString *)my_customMethod;
@end
通过为分类和方法名添加前缀,可以避免与其他框架或库发生命名冲突,提高代码的稳定性和可维护性。
要点
- 向第三方类中添加分类时,总应为其名称和方法名加上专用的前缀。
第26条:勿在分类中声明属性
在Objective-C中,除了使用“class-continuation分类”之外,其他分类无法向类中新增实例变量。因此,在分类中声明属性可能导致意外覆盖已存在的属性,造成不可预知的行为。
不要在分类中声明属性
// 错误示例
@interface MyClass (MyCategory)
@property (nonatomic, strong) NSString *myProperty;
@end
如果需要在分类中实现属性,可以使用@dynamic关键字或消息转发机制,但这样的做法并不提倡。最好的实践是将属性定义在主接口中,因为分类的目的是扩展功能而非封装数据。
要点
- 将封装数据所用的全部属性都定义在主接口中。
- 在“class-continuation分类”之外的其他分类中,可以定义存取方法,但尽量不要定义属性。
第27条:使用“class-continuation分类”隐藏实现细节
“class-continuation分类”是一种特殊的分类,它用于向类中新增实例变量和私有方法。通过使用“class-continuation分类”,可以将一些实现细节隐藏起来,只供本类使用。
1. class-continuation分类
// MyClass.m
@interface MyClass ()
@property (nonatomic, strong) NSString *privateProperty;
- (void)privateMethod;
@end
@implementation MyClass
// 类的实现代码
@end
在上述例子中,privateProperty和privateMethod只能在MyClass.m文件中使用,对外部不可见。这种方法可以避免暴露不必要的实
现细节。
2. class-continuation分类的合理用法
class-continuation分类不仅可以用于隐藏实例变量和私有方法,还可以将主接口中声明为“只读”的属性在分类中扩展为“可读写”,以便在类的内部设置其值。
// MyClass.h
@interface MyClass : NSObject
@property (nonatomic, readonly) NSString *readOnlyProperty;
@end
// MyClass.m
@interface MyClass ()
@property (nonatomic, readwrite) NSString *readOnlyProperty;
@end
@implementation MyClass
// 类的实现代码
@end
这种用法既保持了外部只读的特性,又允许内部进行读写操作。
3. 要点
- 通过“class-continuation分类”向类中新增实例变量。
- 在“class-continuation分类”中可以将主接口中声明为“只读”的属性扩展为“可读写”。
- 在“class-continuation分类”中声明私有方法和实例变量。
第28条:通过协议提供匿名对象
在软件开发中,有时需要处理不同实现类的情况,但不希望暴露具体的类名。使用协议提供匿名对象是一种解决方案,可以在一定程度上隐藏实际的对象类型。文章来源:https://www.toymoban.com/news/detail-832552.html
1. 匿名对象
@protocol DatabaseHandler <NSObject>
- (void)connect;
- (void)queryData;
// ... 其他数据库相关方法
@end
@interface DatabaseManager : NSObject
- (id<DatabaseHandler>)getDatabaseHandler;
@end
在上述例子中,DatabaseManager通过协议提供了一个匿名对象,该对象具有处理数据库的能力。外部代码无需关心具体的实现类,只需要使用协议中定义的方法。文章来源地址https://www.toymoban.com/news/detail-832552.html
2. 要点
- 协议可在某种程度上提供匿名类型,通过协议的id类型来表示。
- 使用匿名对象来隐藏具体类型,重要的是对象能够相应协议中定义的方法。
到了这里,关于【Effective Objective-C 2.0】协议与分类的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!