Objective-C中非传统设计模式的探索与实践

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:Objective-C的设计模式不仅仅局限于经典模式,还可以利用其动态特性实现一些非传统的模式。本文介绍了一系列基于Objective-C动态特性的设计模式,包括使用协议代替类继承、通过分类扩展类功能、利用KVC和KVO实现属性访问与观察、使用Blocks作为闭包实现回调和并发、代理模式的变体、消息转发机制、以及利用工厂方法、分类和Category实现单例、分类的分类、私有方法的实现等。这些设计模式提高了代码的灵活性和可维护性,并在实际开发中发挥重要作用。
简单的一些非经典的objc设计模式

1. objc非经典设计模式的理论基础

在Objective-C编程的世界中,传统的设计模式如单例、工厂、策略等被广泛应用,但objc语言特有的灵活性和动态特性,让我们有机会探索一些非传统的设计模式。这些非经典设计模式并不遵循传统的设计原则,但它们利用objc的特性,如动态类型、消息传递和运行时特性,能够提供更简洁或更高效的解决方案。

1.1 设计模式在objc中的演变

设计模式是软件工程中的经典概念,它们是解决特定问题的最佳实践。然而,objc语言的特性让一些经典设计模式在使用时发生了变化,或者产生了更为简洁的替代方案。非经典设计模式正是这些变化和替代方案的体现。

1.2 非经典设计模式的重要性

掌握非经典设计模式对于objc开发者来说至关重要。这不仅能够帮助我们深入理解语言特性,还能够引导我们编写出更加高效和优雅的代码。特别是在框架和库开发过程中,非经典设计模式的使用可以显著提高代码的灵活性和可维护性。

1.3objc语言的特性与设计模式的关系

objc语言的动态特性、协议(Protocols)、分类(Categories)以及块(Blocks)等,为设计模式的实现提供了独特的优势。非经典设计模式的产生往往根植于这些语言特性,它们与objc的运行时特性紧密结合,使得设计模式的实现更加直观和简洁。

在后续的章节中,我们将深入探讨如何利用objc的特性来实现和应用非经典设计模式,以及它们在实际开发中带来的创新和效率。

2. 利用协议实现接口的继承与多态

2.1 协议作为接口的定义和作用

2.1.1 接口的引入与协议的基本用法

在Objective-C中,协议(Protocol)是一种定义一组方法的接口规范,这些方法可以由任何类来实现。协议提供了一种方式,允许不同的类实现同一组方法,而不必关心它们的继承关系。这就像是在不同对象之间建立了一种新的“契约”关系。

协议的基本用法示例如下:

// 定义一个协议
@protocol SomeProtocol <NSObject>
- (void)doSomething;
@end// 类声明遵循协议
@interface SomeClass : NSObject <SomeProtocol>
@end// 类实现协议
@implementation SomeClass
- (void)doSomething {NSLog(@"Doing something!");
}
@end

在上述代码中,我们首先定义了一个名为 SomeProtocol 的协议,并声明了一个名为 doSomething 的方法。随后,我们声明了一个 SomeClass 类,它遵循了 SomeProtocol 协议,并实现了协议中的 doSomething 方法。

2.1.2 协议与类继承的区别和联系

协议与类继承的主要区别在于它们在实现多态的方式上。类继承是基于“is-a”的关系,而协议则是基于“can-do”的能力描述。继承意味着子类将从父类那里获得属性和方法,而协议仅规定了必须实现的方法集合。

从联系上说,协议可以与类继承相结合,形成更灵活的设计。一个类可以同时遵循多个协议,也可以继承自一个类同时遵循多个协议,这为Objective-C中的面向对象设计提供了极高的自由度。

2.2 协议实现多态的方法和优势

2.2.1 协议与多态性结合的场景分析

协议与多态性的结合,可以在不增加类层次复杂度的情况下,提供一种松耦合的扩展机制。比如,使用协议来定义一系列操作,然后让不同的类实现这些协议,从而实现相同的操作在不同对象上具有不同的实现,即多态。

例如,假设我们有一个处理数据的协议 DataHandler

@protocol DataHandler <NSObject>
- (void)processData:(NSData *)data;
@end@interface JSONDataHandler : NSObject <DataHandler>
@end@implementation JSONDataHandler
- (void)processData:(NSData *)data {// 处理JSON数据的逻辑
}
@end@interface XMLDataHandler : NSObject <DataHandler>
@end@implementation XMLDataHandler
- (void)processData:(NSData *)data {// 处理XML数据的逻辑
}
@end

这里, JSONDataHandler XMLDataHandler 都遵循了 DataHandler 协议,并提供了自己对 processData: 方法的实现。这样,当我们需要处理数据时,我们只需要依赖 DataHandler 协议,而不需要关心具体是哪个类来处理的。

2.2.2 利用协议实现面向对象设计的灵活性

协议是Objective-C面向对象编程中的一个关键特性,它允许开发者定义可被多个不同类实现的方法集合。这种机制提供了极高的灵活性和扩展性,特别是在以下方面:

  • 委托模式 :协议常被用作定义委托(Delegate)接口,允许多个对象根据协议实现各自的行为。
  • 数据源 :例如, UITableView 通过协议方法获取数据,这些方法可以由任何遵循 UITableViewDataSource 协议的类实现。
  • 单元测试 :协议使得模拟和测试变得更加容易,因为可以在测试环境中用遵循特定协议的伪对象替代真实对象。
// 定义一个简单的协议
@protocol MyProtocol;
@interface MyClass : NSObject <MyProtocol>
@end// 定义协议
@protocol MyProtocol <NSObject>
- (void)myProtocolMethod;
@end// 实现协议
@implementation MyClass
- (void)myProtocolMethod {NSLog(@"Implementing MyProtocolMethod");
}
@end

在这个例子中,我们定义了一个 MyProtocol 协议,并且 MyClass 类遵循并实现了协议中的方法。这种方式确保了 MyClass 实例能够响应与协议相关的方法调用。

总的来说,协议在Objective-C中的应用提供了程序设计上的灵活性,它可以帮助开发者创建既松耦合又高度可扩展的系统架构。

3. 分类(Category)的高级应用技巧

3.1 分类(Category)扩展类功能的原理和实践

3.1.1 分类的定义及其背后的机制

在 Objective-C 中,分类(Category)是一种强大的语言特性,允许开发者向已有的类中动态添加方法,而不必访问类的源代码,也不需要创建子类。这种机制非常适用于对第三方类库或系统框架进行扩展。分类通过声明一个新的 .h 文件和相应的 .m 文件来定义,其背后的工作原理基于运行时(Runtime)机制。

在运行时,每个对象都持有一个方法列表,分类的实现将新方法添加到这个列表中。编译器在编译阶段会将分类中声明的方法合并到原类的方法列表中,从而实现了对类的扩展。这种方式不会改变原有类的定义,使得分类成为了一种扩展类功能的非侵入式手段。

3.1.2 分类在不同场景下的应用方法

分类的应用场景非常广泛,以下是一些典型的使用案例:

  • 模块化代码 :将不同的功能模块化,每个分类代表一个功能模块。例如,为 NSString 类添加一个分类,专门处理字符串格式化功能。
  • 隐藏私有API :在公共头文件中声明公共接口,将实现细节放在分类中,这样可以保持接口的简洁性,同时将细节隐藏。
  • 避免类的膨胀 :当一个类的功能变得庞大时,可以通过分类来组织和分散代码,使其更易于管理和维护。
  • 代码调试和优化 :将实验性的代码和优化功能放在分类中,不影响现有项目的稳定性和其他功能的正常运行。

3.2 分类与其他设计模式的结合

3.2.1 分类与继承模式的比较

分类和继承都是面向对象编程中的重要概念,它们都可以用于扩展类的功能,但它们有本质的不同:

  • 继承 是一种静态关系,子类通过继承获得父类的所有属性和方法,并可以添加或重写它们。继承是面向对象中的基本关系,但过于紧密,子类和父类之间耦合度较高。
  • 分类 是一种动态关系,它在不改变原类定义的情况下,向类中添加方法。分类更灵活,可以被多个类包含,且与原类解耦。

在实际开发中,选择继承还是分类取决于具体需求。如果需要进行面向对象的多态设计,继承通常是更合适的选择。当需要对第三方类库进行扩展,或希望保持类之间的解耦,分类是更优的选择。

3.2.2 分类实现私有方法的技术剖析

在 Objective-C 中,分类还可以用来封装私有方法。私有方法通常是指那些只在类的实现文件中使用,而不希望在类的外部被调用的方法。通过分类,我们可以将这些私有方法集中管理,而不是散布在类的实现文件中。这不仅有助于保持类的整洁,还可以在需要时轻松地对这些私有方法进行重构。

通过在 .m 文件中声明分类(通常命名为 PrivateCategory ),可以将私有方法声明在其中。但是,需要注意的是,分类中的方法默认是公开的。要实现真正的私有方法,需要采取额外的措施,例如利用编译器的属性控制( static 关键字或使用 __private 属性)来确保这些方法不会被外部访问。

下面是一个简单的例子:

// 在NSString+Private.h文件中
@interface NSString (Private)
- (void)privateMethod;
@end// 在NSString+Private.m文件中
@implementation NSString (Private)
- (void)privateMethod {// 私有方法的实现
}
@end

请注意,虽然分类使得私有方法更容易被访问,但最佳实践是不要过分依赖分类来实现真正的私有功能,因为运行时仍然可以通过反射访问这些方法。更安全的私有方法实现方式包括使用类扩展(class extensions)或者将私有方法放在实现文件中不进行声明。

@interface NSString ()
- (void)_reallyPrivateMethod;
@end

通过上述方法,可以安全地将方法定义为真正的私有方法,因为它们不会出现在类的公开接口中,也不会被其他文件访问。

4. KVC与KVO在objc中的数据绑定技术

在Objective-C编程中,KVC(键值编码)和KVO(键值观察)提供了强大的数据绑定和动态观察机制,极大地增强了模型与视图间的解耦和数据的动态交互能力。本章深入探讨这两个技术的基本原理、用途以及如何在项目中实现数据绑定和属性观察的案例。

4.1 KVC与KVO的基本原理和用途

4.1.1 KVC的键值编码机制解析

KVC允许我们通过字符串的键(key)直接访问和设置对象的属性,而无需调用该属性的setter和getter方法。这通过Objective-C运行时的特性来实现,使得动态语言的特性在编译时静态语言中得到体现。

在KVC中,我们经常使用 valueForKey: setValue:forKey: 来访问和修改属性。需要注意的是,如果访问不存在的键,程序会抛出异常。

// 使用KVC设置对象的属性值
Person *person = [[Person alloc] init];
[person setValue:@"John Doe" forKey:@"name"];
// 使用KVC获取对象的属性值
NSString *name = [person valueForKey:@"name"];
代码逻辑的逐行解读分析
  • Person *person = [[Person alloc] init]; 创建了一个Person类的实例。
  • [person setValue:@"John Doe" forKey:@"name"]; 通过KVC机制,将name属性的值设置为”John Doe”。
  • NSString *name = [person valueForKey:@"name"]; 通过KVC获取person对象name属性的值,并将该值存储到字符串变量name中。

4.1.2 KVO的键值观察模式实现细节

KVO是一种观察者模式的实现,它允许对象监听其他对象属性值的变化。当被观察对象的属性值改变时,观察者对象会收到通知。KVO利用Objective-C运行时动态地为对象添加属性的getter和setter方法,从而实现对属性变化的监控。

// 注册观察者
[person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];// 被观察者属性变化
[person setName:@"Jane Doe"];// 实现观察者回调方法
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {if ([keyPath isEqualToString:@"name"]) {NSString *newValue = change[NSKeyValueChangeNewKey];NSLog(@"新名字是: %@", newValue);}
}
代码逻辑的逐行解读分析
  • [person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil]; 在person对象上注册一个观察者,观察其name属性的变化。
  • [person setName:@"Jane Doe"]; 更改person对象的name属性值。
  • observeValueForKeyPath:ofObject:change:context: 当被观察的属性值变化时,这个方法会被调用,我们在这个方法中可以根据属性键(keyPath)判断具体哪个属性发生了变化,并进行相应的操作。

4.2 利用KVC与KVO进行数据绑定和属性观察的案例

4.2.1 数据绑定在模型与视图之间的应用

数据绑定是将视图的属性与模型的属性进行关联,当模型属性改变时,视图会自动更新。KVC和KVO能够有效地在模型和视图之间建立这种动态的绑定关系。

以一个简单的用户界面为例,我们要实现一个文本框显示用户的姓名,当模型中用户的姓名属性更新时,文本框中显示的姓名也自动更新。

graph LR;
A[模型Model] -->|KVO监听| B[数据同步]
B --> C[更新视图View]
数据绑定流程说明
  1. 模型Model :定义用户的数据模型,包含用户的姓名等属性。
  2. 数据同步 :当Model中的用户姓名属性被修改时,KVO机制会触发通知,数据同步过程开始。
  3. 更新视图View :将新的数据(新的姓名)更新到界面的文本框组件。

4.2.2 属性观察在业务逻辑中的实践技巧

在业务逻辑层,使用KVO不仅可以监控数据的变化,还能根据数据的变化做出相应的业务处理。例如,我们可以基于用户的登录状态变化来更新应用的导航栏显示。

// 用户类User
@interface User : NSObject
@property (nonatomic, assign) NSInteger loginStatus;
@end// 观察用户登录状态变化
[self.user addObserver:self forKeyPath:@"loginStatus" options:NSKeyValueObservingOptionNew context:nil];// 实现观察回调方法
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {if ([keyPath isEqualToString:@"loginStatus"]) {NSInteger newStatus = [change[NSKeyValueChangeNewKey] integerValue];if (newStatus == 1) {// 用户已登录,更新导航栏显示self.navigationItem.title = @"欢迎回来";} else {// 用户未登录,更新导航栏显示self.navigationItem.title = @"欢迎";}}
}
代码逻辑的逐行解读分析
  • [self.user addObserver:self forKeyPath:@"loginStatus" options:NSKeyValueObservingOptionNew context:nil]; 在用户对象上注册观察者,监听loginStatus属性。
  • [change[NSKeyValueChangeNewKey] integerValue] 获取属性变化后的值。
  • if (newStatus == 1) 判断用户登录状态是否为已登录,并根据状态更新导航栏标题。

通过这样的实践,KVC和KVO不仅仅提供了数据绑定和属性观察的机制,同时也丰富了我们在处理动态数据交互时的编程策略和方法。

5. Blocks与闭包在objc中的实现与运用

5.1 Blocks的定义和闭包的基本概念

5.1.1 Blocks的语法和内存管理

Blocks是Objective-C中一种特殊的代码块,它能将一段代码及其相关的状态封装起来,从而形成一个可以复用的功能块。在Objective-C中,它通常被用来实现回调函数、操作列表、排序和异步执行等任务。

Blocks的语法使用了 ^ 符号来定义,它可以捕获在代码块创建时外部变量的值,使得即使外部变量在Block创建后改变了,Block内依然可以使用这些变量的值。但这种捕获可能会带来内存管理方面的问题,特别是当捕获的变量是引用类型时(如对象)。

void (^myBlock)(void) = ^{NSLog(@"Block内部可以访问到外部的变量");
};// 执行Block
myBlock();

从上面的简单例子中可以看到,Block在Objective-C中被定义为 void (^blockName)(void) 这样的形式。当Block内部引用了外部的局部变量时,Block会创建这些变量的复制,并在内部使用这些复制的值。

关于内存管理,由于Block实际上是一个引用类型,所以当它被创建在一个自动释放池中时,需要特别注意引用计数。例如,当Block被赋值给一个属性,或者作为回调方法的参数传递时,可能需要对Block进行 copy 操作,以确保Block在适当的时候不被释放。

5.1.2 闭包在objc中的定义和作用

闭包(Closure)是编程语言中一个可执行代码块的表达式,它能捕获周围状态的值。在Objective-C中,Blocks可以被视为闭包的一种实现方式。闭包允许开发者在代码中创建函数类型的实例,这些实例可以捕获并存储其定义时所在的作用域中变量的引用。这种特性使闭包非常适合实现回调、事件处理器、数据封装等功能。

Objective-C中的闭包有以下几个主要作用:

  • 封装代码 :将多行代码封装成一个单独的代码块,可以在之后的程序执行中多次调用。
  • 参数传递 :可以像传递普通数据类型一样传递代码块,实现高度的灵活性。
  • 访问外部变量 :闭包可以捕获其定义时作用域中的变量,并在执行时引用这些变量。

5.2 Blocks在objc中的高级用途

5.2.1 Blocks在回调和异步处理中的应用

在异步处理和回调机制中,Blocks提供了极大的便利性。由于Blocks可以捕获并存储作用域中的变量值,因此它在异步编程模型中可以用来简化数据传递的流程。

比如,在网络请求中,通常需要一个回调函数来处理请求成功或失败的情况。使用Blocks可以将成功或失败的处理逻辑写在请求方法中,而不需要单独定义回调函数:

NSURL *url = [NSURL URLWithString:@"http://example.com/data.json"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
__block NSError *error = nil;
__weak __typeof(self) weakSelf = self;[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {weakSelf.progressBlock(data); // 更新进度if (connectionError) {error = connectionError;} else {NSError *parseError = nil;id jsonObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&parseError];if (parseError) {error = parseError;} else {weakSelf.jsonBlock(jsonObject); // 成功处理数据}}if (error) {NSLog(@"请求错误:%@", error);}
}];

在上面的示例中, progressBlock jsonBlock 是Block类型的属性,它们被用作异步请求完成后的回调处理。

5.2.2 利用Blocks实现数据封装和函数式编程

由于Blocks提供了代码封装的便利性,它可以用来实现函数式编程中的某些特性,比如“高阶函数”。在Objective-C中,可以使用Blocks作为参数或者返回值,实现对数据的封装和函数的组合。

利用Blocks的这种能力,可以实现一些简单的函数式编程技术。例如,可以使用Blocks作为参数来过滤数组:

NSArray *numbers = @[@1, @2, @3, @4, @5];
NSArray *evenNumbers = [numbers filteredArrayUsingBlock:^BOOL(id obj, NSUInteger idx, BOOL *stop) {return [obj isEqual:@([obj unsignedIntegerValue] % 2 == 0)];
}];

在这个例子中, filteredArrayUsingBlock: 方法使用了一个Block作为过滤条件,返回数组中所有偶数的数组。这种使用Blocks的方式使得代码更加灵活且易于阅读。

总的来说,Blocks在Objective-C中的应用不仅限于回调和异步处理,它们还提供了数据封装和函数式编程的强大工具,使得Objective-C的编程风格更加现代化和灵活。在实际开发中,合理利用Blocks能显著提高代码的可维护性和执行效率。

6. 代理(Delegate)模式的变体与实例

6.1 代理模式的原理和objc中的实现

6.1.1 代理模式的基本思想

代理模式是一种常见的设计模式,用于表示一种行为的接口,使得其他对象可以在这个接口的约束下执行一些特定的操作。其核心思想是将某些操作委托给其他对象来执行,以保持代码的松耦合和可扩展性。

在软件设计中,代理模式经常被用于实现以下几个目标:

  1. 控制对一个对象的访问;
  2. 当对象的某些操作变得过于复杂时,简化对象的使用;
  3. 当一个对象的生命周期需要被外部管理时。

6.1.2 在objc中实现代理模式的方法

在Objective-C中,代理模式是通过协议(Protocol)和委托(Delegate)属性来实现的。协议定义了一组方法,类可以声明它遵循这些方法,但不必实现它们。委托则是实现了这些协议的类的实例。

示例代码块
// 定义一个协议,包含代理方法
@protocol MyDelegate <NSObject>
- (void)delegateMethodToHandleAction:(NSString *)action;
@end// 类A实现了协议,作为代理
@interface ClassA : NSObject <MyDelegate>
@property (nonatomic, weak) id<MyDelegate> delegate;
@end@implementation ClassA- (void)performAction {// 假设发生了一个需要通知代理的事件[self.delegate delegateMethodToHandleAction:@"action"];
}@end// 类B遵循协议,并注册为A的代理
@interface ClassB : NSObject <MyDelegate>
@end@implementation ClassB- (void)delegateMethodToHandleAction:(NSString *)action {NSLog(@"ClassB handled action: %@", action);
}@end// 使用时,创建A和B的实例,并将B设置为A的代理
ClassA *a = [[ClassA alloc] init];
ClassB *b = [[ClassB alloc] init];
a.delegate = b;// 调用方法,触发代理方法
[a performAction];

在这个例子中, ClassA 需要执行某些操作时,它通过它的 delegate 属性调用 delegateMethodToHandleAction: 方法。 ClassB 实现了这个协议,并被设置为 ClassA 的代理,从而响应代理消息。

6.2 探索代理模式的变体和扩展应用

6.2.1 多代理模式的实现和适用场景

在某些复杂的场景下,单一的代理可能不足以满足需求。多代理模式允许多个对象同时作为代理,共同响应代理消息。这在需要多个对象协作处理同一个事件时非常有用。

示例代码块
// 多代理需要遵循协议的类实现可选的方法
@protocol MultiDelegate <NSObject>
@optional
- (void)optionalMethodForMultipleDelegates;
@end// 类C和D都遵循这个协议
@interface ClassC : NSObject <MultiDelegate>
@end@implementation ClassC- (void)optionalMethodForMultipleDelegates {NSLog(@"ClassC handled optional method");
}@end@interface ClassD : NSObject <MultiDelegate>
@end@implementation ClassD- (void)optionalMethodForMultipleDelegates {NSLog(@"ClassD handled optional method");
}@end// 类E可以拥有多个代理
@interface ClassE : NSObject
@property (nonatomic, weak) id<MultiDelegate> delegate1;
@property (nonatomic, weak) id<MultiDelegate> delegate2;
@end@implementation ClassE- (void)triggerMultipleDelegates {if ([self.delegate1 respondsToSelector:@selector(optionalMethodForMultipleDelegates)]) {[self.delegate1 optionalMethodForMultipleDelegates];}if ([self.delegate2 respondsToSelector:@selector(optionalMethodForMultipleDelegates)]) {[self.delegate2 optionalMethodForMultipleDelegates];}
}@end// 使用时,创建E的实例,并将C和D设置为E的多个代理
ClassE *e = [[ClassE alloc] init];
ClassC *c = [[ClassC alloc] init];
ClassD *d = [[ClassD alloc] init];
e.delegate1 = c;
e.delegate2 = d;// 调用方法,触发多个代理
[e triggerMultipleDelegates];
6.2.2 委托模式与通知结合的设计思路

委托模式与通知模式结合可以创建更加灵活的设计,它允许对象在不直接知道对方的情况下进行通信。一个对象可以通知一个中间对象,而这个中间对象再转发通知到其他监听的代理对象。

示例代码块
// 使用NSNotificationCenter实现通知的发送和监听
// 假设ClassF需要向其他对象发送通知
ClassF *f = [[ClassF alloc] init];// 注册监听者
[[NSNotificationCenter defaultCenter] addObserver:selfselector:@selector(handleNotification:)name:@"MyNotification"object:f];// ClassF发送通知
[[NSNotificationCenter defaultCenter] postNotificationName:@"MyNotification"object:f];// 在监听者对象中实现handleNotification:方法来响应通知
- (void)handleNotification:(NSNotification *)notification {NSLog(@"Received notification: %@", notification.name);
}// 别忘了在不需要监听时移除监听者
- (void)dealloc {[[NSNotificationCenter defaultCenter] removeObserver:self];
}

通过这种方式,类F可以通知其他对象进行操作,而这些对象并不需要直接引用类F。这种模式在需要解耦的对象间通信中非常有用。

7. objc中消息转发机制与工厂方法的综合应用

在Objective-C编程中,消息转发机制和工厂方法是两种重要的面向对象设计技术。它们在运行时动态地处理方法调用和对象的创建过程,从而提供更大的灵活性和扩展性。

7.1 消息转发机制的深入理解和使用

7.1.1 消息转发的工作原理

Objective-C的消息转发机制允许对象有机会响应原本未定义的消息。当一个消息发送给对象,但该对象没有实现相应的方法时,系统会按照一定顺序尝试解决这个问题:

  1. 动态方法解析:运行时首先调用对象的 +resolveInstanceMethod: +resolveClassMethod: 方法。开发者可以在这里动态添加方法实现。
  2. 快速转发(Fast Forwarding):如果没有方法被解析,运行时会调用对象的 forwardingTargetForSelector: 方法,允许开发者将消息转发给另一个对象处理。

  3. 完整转发(Full Forwarding):如果快速转发没有处理,运行时最后会调用对象的 methodSignatureForSelector: forwardInvocation: 方法。在 forwardInvocation: 中,开发者可以使用NSInvocation对象,封装消息并进行更复杂的转发。

7.1.2 如何利用消息转发解决方法调用问题

消息转发可以用来处理很多边界情况,例如:

  • 动态代理:可以创建一个中介对象,负责转发消息给实际处理者。
  • 模拟方法实现:当某些类的方法实现不可更改时,可以通过消息转发提供额外的处理逻辑。
  • 抽象接口:定义抽象接口,并在运行时决定具体的实现类。

消息转发不仅可以增加程序的灵活性,还可以作为编程时的一种设计模式,用于实现延迟加载、插件系统等功能。

7.2 工厂方法与分类结合的实例化模式

7.2.1 工厂方法在objc中的实现策略

工厂方法是一种创建型设计模式,它提供了一种创建对象的最佳方式。在Objective-C中,工厂方法通常使用类方法实现,并返回一个类的实例。结合分类(Category),可以在不修改原有类的情况下,为类添加工厂方法,实现具体的实例化逻辑。

一个工厂方法的实现步骤可能如下:

  1. 定义一个类方法,返回自定义类类型的实例。
  2. 在工厂方法中执行必要的初始化操作。
  3. 遵循单一职责原则,每个工厂方法负责创建一种类型的对象。

示例代码:

@interface CustomClass : NSObject
+ (instancetype)customFactoryMethod;
@end@implementation CustomClass (Factory)+ (instancetype)customFactoryMethod {CustomClass *object = [[self alloc] init];// Perform any additional setup requiredreturn object;
}@end

7.2.2 结合分类实现更灵活的对象创建过程

分类可以用来增强已有类的功能。结合工厂方法,可以让对象的创建过程更加灵活。例如,可以通过分类为某个类添加多个工厂方法,每个工厂方法对应不同的创建策略。

使用分类添加工厂方法的优点包括:

  • 代码组织清晰:分类可以在逻辑上分离不同的创建策略。
  • 易于扩展:无需修改原有类的情况下,添加新的工厂方法。
  • 隐藏实现细节:客户端代码不需要知道对象的具体创建过程。
@interface CustomClass (FactoryExtension)+ (instancetype)customFactoryMethodWithParameter:(NSString *)parameter;@end@implementation CustomClass (FactoryExtension)+ (instancetype)customFactoryMethodWithParameter:(NSString *)parameter {CustomClass *object = [[self alloc] init];// Use the parameter to configure the objectreturn object;
}@end

7.3 利用Category实现线程安全的单例和其他高级技巧

7.3.1 Category在线程安全单例中的应用

利用分类实现线程安全的单例模式是一种常见的技巧。通过分类,可以将单例的实现封装起来,同时保证线程安全。Objective-C运行时提供了 dispatch_once 函数,这是实现线程安全单例的推荐方式。

示例代码:

@implementation SingletonClass (Singleton)static SingletonClass *_instance = nil;+ (instancetype)sharedInstance {static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{_instance = [[self alloc] init];});return _instance;
}@end

7.3.2 Category实现分类的分类以及其它高级特性

分类的分类(Category of Category),是一种高级技巧,可以为一个已有的分类添加新的方法。这是Objective-C语言的特性之一,允许开发者在不修改原有类定义的情况下,为分类继续增加方法。

示例代码:

// 假设已有的分类
@interface SomeClass (SomeCategory)
- (void现有的方法);
@end// 现在想为这个分类增加新的方法
@interface SomeClass (SomeCategory) (MoreMethods)
- (void新增方法);
@end@implementation SomeClass (SomeCategory) (MoreMethods)
- (void新增方法) {// 新增方法的实现
}
@end

这种方法可以在类库的维护和更新中非常有用,特别是对于第三方库的扩展。

通过上述章节的介绍和示例代码,我们展示了Objective-C中消息转发机制、工厂方法以及Category的高级应用技巧,以及它们在实际编程中的应用。在接下来的章节中,我们将进一步探索如何利用这些技术解决实际开发中的问题。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:Objective-C的设计模式不仅仅局限于经典模式,还可以利用其动态特性实现一些非传统的模式。本文介绍了一系列基于Objective-C动态特性的设计模式,包括使用协议代替类继承、通过分类扩展类功能、利用KVC和KVO实现属性访问与观察、使用Blocks作为闭包实现回调和并发、代理模式的变体、消息转发机制、以及利用工厂方法、分类和Category实现单例、分类的分类、私有方法的实现等。这些设计模式提高了代码的灵活性和可维护性,并在实际开发中发挥重要作用。


本文还有配套的精品资源,点击获取
menu-r.4af5f7ec.gif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/92105.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/92105.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【笔记】重学单片机(51)(下)

中断系统 正常运行过程中&#xff0c;被打断进行另外工作&#xff0c;结束后回到原有进程。 5个中断源 外部中断源&#xff08;2个&#xff09;&#xff1a;INT0——由P3.2端口线引入&#xff0c;低电平或下降沿引起。INT1——由P3.3端口线引入&#xff0c;低电平或下降沿引起。…

Go实现程序启动器进而实现隐藏真实内容

注意&#xff1a; 本文内容于 2025-08-03 01:10:35 创建&#xff0c;可能不会在此平台上进行更新。如果您希望查看最新版本或更多相关内容&#xff0c;请访问原文地址&#xff1a;Go实现程序启动器进而实现隐藏真实内容。感谢您的关注与支持&#xff01; 突发奇想&#xff0c;…

Fiddler 中文版怎么用 实现接口抓包调试与前后端联调闭环

API调试在现代开发流程中的地位愈发重要&#xff1a;接口数量激增、请求逻辑复杂、数据结构多变、安全校验机制加严……一个小小的参数错误、一次隐蔽的跨域问题、一个环境配置疏漏&#xff0c;都可能导致长时间的排查成本。而拥有一款既强大又易用的调试工具&#xff0c;尤其是…

ollama 多实例部署

如果我们需要在一台服务器上使用多个ollama服务&#xff0c;那么我们需要进行将ollama前端和ollama后端对应连接的操作&#xff0c;否则就会出现如下场景&#xff1a;我们可以在当前端口设置&#xff0c;这句话就是指明当前ollama实例使用哪个后端进行请求&#xff1a;export O…

orchestrator部署

场景&#xff1a; 用于管理MySQL高可用 下载jq包 每台orchestrator集群机器上都进行下载。 # wget http://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm # rpm -ivh epel-release-latest-7.noarch.rpm # yum repolist ###检查是否已经添加到源列表 # yum i…

CentOS 6.4 上安装 Oracle 10.2.0.1 并升级到 10.2.0.4

目录 一、系统检查与设置 1. 检查系统版本与磁盘空间 2. 修改系统参数 3. 创建组和用户 4. 设置主机名 5. 检查安装软件包 6. 设置 oracle 用户环境变量 二、安装 Oracle 软件包 1. 安装 10.2.0.1 安装包 2. 安装 10.2.0.4 补丁 三、建库 四、配置监听器 1. 编辑配…

【基于C# + HALCON的工业视系统开发实战】二十六、车规级PCB全自动质检:3D SPI+AI光学检测融合方案

摘要&#xff1a;本文详细阐述基于C# .NET Core 6与HALCON 24.11开发的车规级PCB板AOI智能检测系统&#xff0c;提出3D SPI与AI光学检测融合方案。系统通过结构光3D测量技术实现锡膏印刷质量检测&#xff0c;结合多算法融合的自动光学检测完成元件缺陷识别&#xff0c;构建SPI与…

Go源码解读——互斥锁与读写锁

互斥锁Mutextype Mutex struct {// 表示互斥锁状态state int32// 表示信号量&#xff0c;协程阻塞等待该信号量&#xff0c;解锁的协程释放信号量从而唤醒等待信号量的协程sema uint32 }Locked: 表示该Mutex是否已被锁定&#xff0c;0&#xff1a;没有锁定 1&#xff1a;已被锁…

Linux(centos)安全狗

sdui进入操作页面 [rootlocalhost safedog_an_linux64_2.8.32947]# sdui维护 查看、启动或停止服务。 [rootiZbp1f0xuq9rc41s6gdvfyZ /]# systemctl status safedog [rootiZbp1f0xuq9rc41s6gdvfyZ /]# systemctl start safedog [rootiZbp1f0xuq9rc41s6gdvfyZ /]# systemct…

ES9 / ES2018 正则表达式增强

✅ 一、命名捕获组&#xff08;Named Capture Groups&#xff09;给捕获结果起名字&#xff0c;更易读、更易维护。&#x1f539; 传统写法&#xff08;位置识别&#xff09;&#xff1a;const result /(\d{4})-(\d{2})-(\d{2})/.exec("2025-07-31"); console.log(…

深入Java开发:Token的全方位解析与实战指南(下)

深入Java开发&#xff1a;Token的全方位解析与实战指南&#xff08;下&#xff09; 上一篇 深入Java开发&#xff1a;Token的全方位解析与实战指南&#xff08;上&#xff09; 五、Token 的生命周期与管理 5.1 Token 的生命周期状态 Token 的生命周期涵盖了从创建到最终失效…

第二十四天(数据结构:栈和队列)队列实践请看下一篇

栈和队列栈 &#xff1a; 是限定在表尾进行插入和删除操作的线性表实现是一回事&#xff0c;但是必须要满足栈的基本特点它的设计思路是:先进后出&#xff0c;后进先出栈有两端1 栈顶(top) &#xff1a;插入数据删除数据都只能在这一端访问也只能访问栈顶2 栈底(bottom) : 栈底…

三、Spark 运行环境部署:全面掌握四种核心模式

作者&#xff1a;IvanCodes 日期&#xff1a;2025年7月25日 专栏&#xff1a;Spark教程 Apache Spark 作为统一的大数据分析引擎&#xff0c;以其高性能和灵活性著称。要充分利用Spark的强大能力&#xff0c;首先需要根据不同的应用场景和资源环境&#xff0c;正确地部署其运行…

【Django】-2- 处理HTTP请求

一、request 请求 先理解&#xff1a;Request 是啥&#xff1f;用户访问你的网站时&#xff0c;会发一个 “请求包” &#x1f4e6; &#xff0c;里面装着&#xff1a;想访问啥路径&#xff1f;用啥方法&#xff08;GET/POST 等&#xff09;&#xff1f;带了啥头信息&#xff0…

飞算 JavaAI:突破效率边界的代码智能构造平台

飞算 JavaAI&#xff1a;突破效率边界的代码智能构造平台 一、引言&#xff1a;数字化浪潮下的开发效率困局与破局路径 当企业数字化转型驶入深水区&#xff0c;软件开发正面临需求迭代频次激增、人力成本高企、技术架构复杂化的多重挑战。传统开发模式中&#xff0c;从需求分…

国家科学技术奖答辩PPT案例_科技进步奖ppt制作_技术发明奖ppt设计美化_自然科学奖ppt模板 | WordinPPT

“国家科学技术奖”是在科学技术领域设立的最高荣誉&#xff0c;旨在奖励在科学技术进步活动中做出突出贡献的个人和组织&#xff0c;从而推动国家科学技术事业的发展&#xff0c;加快建设科技强国。科学技术奖是国内科技界的最高殿堂&#xff0c;是对做出杰出贡献的科技工作者…

如何通过黑白棋盘进行定位配准融合?(前后安装的两个相机)

一.总结: 完整流程 &#xff1a;硬件准备 → 数据采集 → 空间统一 → 相机标定&#xff08;内参畸变&#xff09; → 外参求解 → 定位配准融合 → 校验 → 生成映射表 → 上线remap验证 我们场景流程 &#xff1a;硬件准备 → 数据采集 → 空间统一 → 定位配准融合 → …

【node】token的生成与解析配置

在用户登录成功之后为了记录用户的登录状态通常会将用户信息编写为一个token&#xff0c;通过解析token判断用户是否登录。 token的生成 JSON Web Token&#xff08;JWT&#xff09; 是一种基于JSON的轻量级身份验证和授权机制。它是一种开放标准&#xff08;RFC 7519&#xff…

yolo 、Pytorch (5)IOU

一、简介 IOU的全称为交并比&#xff08;Intersection over Union&#xff09;&#xff0c;是目标检测中使用的一个概念&#xff0c;IoU计算的是“预测的边框”和“真实的边框”的交叠率&#xff0c;即它们的交集和并集的比值。最理想情况是完全重叠&#xff0c;即比值为1。 …

【银河麒麟服务器系统】自定义ISO镜像更新内核版本

自定义ISO镜像更新内核版本 镜像制作流程 环境 更新仓库 准备新版本内核包 内核清单简介 已下载软件包版本 更新内核包 更新镜像源 制作自动化镜像 修改引导 修改UEFI引导 传统引导 修改ks文件内容 打包镜像 mkisofs参数说明 封装镜像命令 常见问题解决方案 镜像制作流程 #merm…