学习目标
- 理解协议(Protocol)的概念及其在Objective-C中的作用。
- 掌握如何定义协议、实现协议和检查协议实现。
- 理解分类(Category)的概念及其在Objective-C中的作用。
- 掌握如何创建分类和使用分类扩展已有类的功能。
- 了解分类与子类的区别。
学习内容
1. 协议(Protocol)
协议是Objective-C中定义方法列表的一种方式,它声明了一组方法,但不提供实现。任何类都可以选择实现协议中的方法。协议类似于Java中的接口或C++中的纯虚类。
1.1 协议的定义
协议使用 @protocol 关键字定义,语法如下:
@protocol ProtocolName
// 方法声明
@required // 必须实现的方法(默认)
- (void)requiredMethod;
@optional // 可选实现的方法
- (void)optionalMethod;
@end
@required:标记的方法必须由实现该协议的类实现(默认)。@optional:标记的方法可以选择性实现。
示例:
// 定义一个名为Printable的协议
@protocol Printable
- (void)print;
@optional
- (NSString *)description;
@end
1.2 协议的实现
类通过 <ProtocolName> 语法声明实现协议,并在类中实现协议中的方法:
@interface ClassName : SuperClass <Protocol1, Protocol2>
// 类定义
@end
示例:
// Document.h
@interface Document : NSObject <Printable>
@property (nonatomic, copy) NSString *title;
@end
// Document.m
@implementation Document
- (void)print {
NSLog(@"Printing document: %@", self.title);
}
// 可选实现
- (NSString *)description {
return [NSString stringWithFormat:@"Document: %@", self.title];
}
@end
1.3 协议的使用
可以通过 conformsToProtocol: 方法检查对象是否实现了某个协议:
id obj = [[Document alloc] init];
if ([obj conformsToProtocol:@protocol(Printable)]) {
// 对象实现了Printable协议
if ([obj respondsToSelector:@selector(print)]) {
[obj print];
}
}
1.4 协议作为类型
协议可以作为类型使用,表示任何实现了该协议的对象:
- (void)printObject:(id<Printable>)printableObject {
[printableObject print];
}
1.5 协议继承
协议可以继承其他协议:
@protocol AdvancedPrintable <Printable>
- (void)printWithColor:(UIColor *)color;
@end
2. 分类(Category)
分类是Objective-C中一种强大的机制,允许在不修改原始类的情况下,为现有类添加新的方法。
2.1 分类的定义
分类使用 @interface 关键字定义,语法如下:
@interface ClassName (CategoryName)
// 方法声明
@end
示例:
// NSString+Utilities.h
@interface NSString (Utilities)
- (BOOL)isValidEmail;
- (NSString *)reverseString;
@end
// NSString+Utilities.m
@implementation NSString (Utilities)
- (BOOL)isValidEmail {
// 简单的邮箱验证
NSString *emailRegex = @"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}";
NSPredicate *emailTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", emailRegex];
return [emailTest evaluateWithObject:self];
}
- (NSString *)reverseString {
NSMutableString *reversedString = [NSMutableString string];
NSInteger charIndex = [self length];
while (charIndex > 0) {
charIndex--;
NSRange subStrRange = NSMakeRange(charIndex, 1);
[reversedString appendString:[self substringWithRange:subStrRange]];
}
return reversedString;
}
@end
2.2 分类的使用
分类中的方法会成为原始类的一部分,可以直接调用:
NSString *email = @"test@example.com";
if ([email isValidEmail]) {
NSLog(@"Valid email");
}
NSString *original = @"Hello";
NSString *reversed = [original reverseString]; // olleH
2.3 分类的注意事项
- 不能添加实例变量:分类只能添加方法,不能添加实例变量或属性(但可以使用关联对象实现类似功能)。
- 方法名冲突:如果分类中的方法与原始类或其他分类中的方法同名,调用哪个方法是不确定的。
- 覆盖原始方法:虽然技术上可以覆盖原始类的方法,但不推荐这样做,因为无法调用原始实现。
2.4 分类与子类的区别
| 特性 | 分类 | 子类 |
|---|---|---|
| 添加方法 | 可以 | 可以 |
| 添加实例变量 | 不可以 | 可以 |
| 覆盖方法 | 可以(不推荐) | 可以 |
| 调用原始实现 | 不可以 | 可以(通过super) |
| 适用范围 | 所有该类的实例 | 仅子类实例 |
3. 类扩展(Class Extension)
类扩展是一种特殊的分类,没有名称(匿名分类),通常用于:
- 声明私有方法和属性
- 重新声明可读写属性
// Person.m
@interface Person ()
@property (nonatomic, copy) NSString *privateID;
- (void)privateMethod;
@end
@implementation Person
// 实现
@end
练习
- 定义一个
Drawable协议,包含draw方法(必须实现)和erase方法(可选实现)。创建Circle和Rectangle类实现该协议。 - 为
NSArray创建一个分类,添加sum方法(计算所有NSNumber元素的和)和average方法(计算平均值)。 - 为
UIView创建一个分类,添加fadeIn和fadeOut动画方法。 - 创建一个类扩展,为
Person类添加私有属性和方法。 - 比较分类和子类的使用场景,说明在什么情况下应该使用分类而不是子类。
总结
今天我们学习了Objective-C中两个重要的特性:协议和分类。协议定义了一组方法规范,任何类都可以选择实现这些方法,实现了代码的解耦和多态。分类则允许我们为现有类添加新方法,而不需要创建子类或修改原始类。这两种机制都是Objective-C动态特性的体现,极大地增强了代码的灵活性和可扩展性。明天我们将学习Objective-C中的内存管理高级话题。

775

被折叠的 条评论
为什么被折叠?



