MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Objective-C中的@protocol与协议对象化语法

2021-10-255.5k 阅读

Objective-C 协议基础概念

在 Objective-C 编程中,@protocol 是一种重要的语言特性,它定义了一个方法列表,任何类都可以声称遵循(adopt)这个协议,意味着该类承诺实现协议中定义的方法。协议就像是一种契约,它规定了类应该提供哪些行为,但并不关心这些行为具体如何实现。

协议的定义使用 @protocol 关键字,语法如下:

@protocol ProtocolName <NSObject>
// 方法声明列表
- (void)method1;
- (NSString *)method2WithParameter:(NSString *)param;
@end

在上述代码中,@protocol 定义了一个名为 ProtocolName 的协议,<NSObject> 表示该协议继承自 NSObject 协议,NSObject 协议定义了一些所有对象都应该实现的基本方法,如 descriptionhash 等。协议内可以声明实例方法(如 method1method2WithParameter:),默认情况下,这些方法都是必须实现的。

可选方法与必须方法

有时候,我们希望协议中的某些方法是可选的,即遵循该协议的类可以选择是否实现这些方法。在 Objective-C 中,通过 @optional@required 关键字来区分协议中的可选方法和必须方法。@required 是默认的,即如果不明确指定,协议中声明的方法都是必须实现的。

@protocol MyProtocol <NSObject>
@required
- (void)requiredMethod;

@optional
- (void)optionalMethod;
@end

在上述协议 MyProtocol 中,requiredMethod 是必须实现的方法,而 optionalMethod 是可选方法。当一个类遵循 MyProtocol 协议时,编译器会强制要求实现 requiredMethod,但不会对 optionalMethod 进行强制要求。

类遵循协议

当一个类想要遵循某个协议时,在类的声明中使用尖括号 <> 来指定遵循的协议。例如:

@interface MyClass : NSObject <MyProtocol>
// 类的其他声明
@end

@implementation MyClass
- (void)requiredMethod {
    // 实现必须方法
    NSLog(@"Implementing required method.");
}
@end

在上述代码中,MyClass 类声明遵循 MyProtocol 协议,并实现了 requiredMethod。如果 MyClass 没有实现 requiredMethod,编译器会发出警告。

协议对象化语法

协议作为类型

在 Objective-C 中,协议可以作为一种类型来使用。这意味着我们可以声明一个变量、属性或方法参数的类型为某个协议类型。例如:

@protocol Printable <NSObject>
- (void)print;
@end

@interface Printer : NSObject
@property (nonatomic, weak) id<Printable> printableObject;
- (void)printObject;
@end

@implementation Printer
- (void)printObject {
    if ([self.printableObject respondsToSelector:@selector(print)]) {
        [self.printableObject print];
    }
}
@end

@interface Book : NSObject <Printable>
@property (nonatomic, copy) NSString *title;
- (void)print;
@end

@implementation Book
- (void)print {
    NSLog(@"Book Title: %@", self.title);
}
@end

// 使用示例
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Book *book = [[Book alloc] init];
        book.title = @"Objective-C Programming";

        Printer *printer = [[Printer alloc] init];
        printer.printableObject = book;
        [printer printObject];
    }
    return 0;
}

在上述代码中,Printable 协议定义了一个 print 方法。Printer 类有一个属性 printableObject,其类型为 id<Printable>,表示任何遵循 Printable 协议的对象都可以赋值给这个属性。Book 类遵循 Printable 协议并实现了 print 方法。在 main 函数中,我们创建了一个 Book 对象并赋值给 PrinterprintableObject 属性,然后调用 printObject 方法来打印 Book 的信息。

协议对象

从 iOS 15 和 macOS 12 开始,Objective-C 引入了协议对象化语法,使得协议可以像类一样被实例化。协议对象可以通过 @protocol(ProtocolName) 语法来创建。例如:

@protocol MyProtocol <NSObject>
- (void)myMethod;
@end

id myProtocolObject = @protocol(MyProtocol);

在上述代码中,myProtocolObject 是一个协议对象,它代表了 MyProtocol 协议。协议对象可以用于各种用途,比如在运行时检查某个对象是否遵循特定协议。

使用协议对象检查协议遵循情况

协议对象可以用于在运行时检查某个对象是否遵循特定协议。例如:

@protocol MyProtocol <NSObject>
- (void)myMethod;
@end

@interface MyClass : NSObject <MyProtocol>
- (void)myMethod;
@end

@implementation MyClass
- (void)myMethod {
    NSLog(@"MyClass is implementing MyProtocol method.");
}
@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        MyClass *obj = [[MyClass alloc] init];
        id myProtocolObject = @protocol(MyProtocol);

        if ([obj conformsToProtocol:myProtocolObject]) {
            NSLog(@"obj conforms to MyProtocol.");
        } else {
            NSLog(@"obj does not conform to MyProtocol.");
        }
    }
    return 0;
}

在上述代码中,我们创建了一个 MyClass 对象 obj 和一个代表 MyProtocol 的协议对象 myProtocolObject。然后使用 conformsToProtocol: 方法来检查 obj 是否遵循 MyProtocol 协议。

协议的继承

单一继承

协议可以继承自其他协议,就像类继承自其他类一样。通过协议继承,一个协议可以获得父协议中定义的所有方法。例如:

@protocol BasicProtocol <NSObject>
- (void)basicMethod;
@end

@protocol AdvancedProtocol <BasicProtocol>
- (void)advancedMethod;
@end

@interface MyClass : NSObject <AdvancedProtocol>
- (void)basicMethod;
- (void)advancedMethod;
@end

@implementation MyClass
- (void)basicMethod {
    NSLog(@"Implementing basic method.");
}

- (void)advancedMethod {
    NSLog(@"Implementing advanced method.");
}
@end

在上述代码中,AdvancedProtocol 继承自 BasicProtocolMyClass 遵循 AdvancedProtocol,因此它需要实现 BasicProtocol 中的 basicMethodAdvancedProtocol 中的 advancedMethod

多重继承

虽然 Objective-C 类不支持多重继承,但协议支持多重继承。一个协议可以继承自多个协议,语法如下:

@protocol ProtocolA <NSObject>
- (void)methodA;
@end

@protocol ProtocolB <NSObject>
- (void)methodB;
@end

@protocol CombinedProtocol <ProtocolA, ProtocolB>
- (void)methodC;
@end

@interface MyClass : NSObject <CombinedProtocol>
- (void)methodA;
- (void)methodB;
- (void)methodC;
@end

@implementation MyClass
- (void)methodA {
    NSLog(@"Implementing methodA.");
}

- (void)methodB {
    NSLog(@"Implementing methodB.");
}

- (void)methodC {
    NSLog(@"Implementing methodC.");
}
@end

在上述代码中,CombinedProtocol 继承自 ProtocolAProtocolBMyClass 遵循 CombinedProtocol,所以需要实现 ProtocolA 中的 methodAProtocolB 中的 methodB 以及 CombinedProtocol 中的 methodC

协议与代理模式

代理模式概述

代理模式是一种常用的设计模式,在 Objective-C 中,协议常常与代理模式结合使用。代理模式的核心思想是一个对象(代理对象)代表另一个对象(被代理对象)来处理某些任务。在 iOS 开发中,代理模式常用于视图控制器之间的通信、视图与数据模型之间的交互等场景。

协议在代理模式中的应用

在代理模式中,通常会定义一个协议来规定代理对象应该实现的方法。例如,假设我们有一个 ViewController 类,它有一个 UITextField,当用户在 UITextField 中输入内容时,我们希望通知另一个对象(代理对象)。我们可以这样实现:

@protocol TextFieldDelegate <NSObject>
@optional
- (void)textFieldDidChange:(UITextField *)textField;
@end

@interface ViewController : UIViewController
@property (nonatomic, weak) id<TextFieldDelegate> delegate;
@property (nonatomic, strong) UITextField *textField;
@end

@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    self.textField = [[UITextField alloc] initWithFrame:CGRectMake(100, 100, 200, 30)];
    [self.textField addTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
    [self.view addSubview:self.textField];
}

- (void)textFieldDidChange:(UITextField *)textField {
    if ([self.delegate respondsToSelector:@selector(textFieldDidChange:)]) {
        [self.delegate textFieldDidChange:textField];
    }
}
@end

@interface AnotherClass : NSObject <TextFieldDelegate>
- (void)textFieldDidChange:(UITextField *)textField;
@end

@implementation AnotherClass
- (void)textFieldDidChange:(UITextField *)textField {
    NSLog(@"Text in text field changed: %@", textField.text);
}
@end

// 使用示例
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        UIApplication *application = [UIApplication sharedApplication];
        ViewController *viewController = [[ViewController alloc] init];
        AnotherClass *anotherClass = [[AnotherClass alloc] init];
        viewController.delegate = anotherClass;

        // 模拟用户输入
        viewController.textField.text = @"New Text";
    }
    return 0;
}

在上述代码中,TextFieldDelegate 协议定义了 textFieldDidChange: 方法。ViewController 类有一个 delegate 属性,其类型为 id<TextFieldDelegate>,表示任何遵循 TextFieldDelegate 协议的对象都可以作为代理。当 UITextField 的文本发生变化时,ViewController 会检查代理是否实现了 textFieldDidChange: 方法,如果实现了则调用该方法。AnotherClass 遵循 TextFieldDelegate 协议并实现了 textFieldDidChange: 方法,所以当 UITextField 文本变化时,AnotherClasstextFieldDidChange: 方法会被调用。

协议的局限性与注意事项

方法实现

协议只定义了方法的声明,并没有提供方法的实现。遵循协议的类必须自己实现协议中定义的方法。这就要求开发者在实现协议方法时要确保方法的正确性和一致性。

继承关系

虽然协议支持多重继承,但在实际使用中,过多的多重继承可能会导致协议的复杂性增加,难以维护。因此,在设计协议时,应该尽量保持协议的简洁和单一职责。

协议与类的关系

协议并不依赖于特定的类层次结构,一个类可以遵循多个协议,不同类层次结构的类也可以遵循同一个协议。这使得协议在实现代码复用和灵活性方面具有很大优势,但同时也需要开发者更加注意协议的使用场景和约束。

运行时检查

在使用协议对象化语法进行运行时检查时,需要注意 conformsToProtocol: 方法只是检查对象在编译时声明遵循了某个协议,并不保证对象在运行时一定实现了协议中的所有方法。对于可选方法,即使对象声称遵循协议,也可能没有实现可选方法,因此在调用方法前需要使用 respondsToSelector: 进行检查。

总之,在 Objective-C 中,@protocol 和协议对象化语法是强大的编程工具,合理使用它们可以提高代码的可维护性、可扩展性和复用性,但同时也需要开发者深入理解其原理和使用方法,以避免潜在的问题。通过掌握协议的基础概念、对象化语法、继承关系以及在代理模式中的应用等方面,开发者能够更加熟练地运用 Objective-C 进行高效的编程开发。无论是在 iOS 应用开发还是 macOS 应用开发中,协议都在构建灵活、可维护的软件架构中发挥着重要作用。在实际项目中,根据具体需求精心设计协议,能够有效提高代码质量,降低开发成本,为用户带来更好的使用体验。在面向对象编程的世界里,协议就像是连接不同对象之间的桥梁,使得对象之间能够按照约定进行交互,共同完成复杂的功能。随着技术的不断发展,虽然新的编程语言和框架不断涌现,但 Objective-C 的协议特性依然在许多项目中展现着其独特的魅力和价值,值得开发者深入学习和研究。在处理大型项目时,良好的协议设计可以将复杂的功能模块进行合理拆分,各个模块通过协议进行交互,使得整个项目结构更加清晰,易于团队协作开发和后期维护。同时,协议对象化语法为运行时的动态操作提供了更多的可能性,开发者可以根据实际情况灵活地检查对象的协议遵循情况,实现更加智能和自适应的功能。例如,在一些插件化的应用开发中,可以利用协议对象化语法在运行时加载符合特定协议的插件,从而实现应用功能的动态扩展。在移动应用开发中,随着用户需求的不断变化和多样化,灵活运用协议和协议对象化语法能够更好地应对这些变化,使得应用在保持稳定的基础上不断进化和优化。总之,深入理解和掌握 Objective-C 中的 @protocol 与协议对象化语法是每一位 Objective-C 开发者不可或缺的技能,它将为开发者打开通往高效、灵活编程的大门,助力开发者创造出更加优秀的软件产品。