赞
踩
目录
4. KVC 和 KVO(Key-Value Coding 和 Key-Value Observing)
MVC(Model-View-Controller)是一种常见的软件设计模式,旨在将应用程序的逻辑、用户界面和输入进行分离。
在iOS开发中,MVC帮助开发者组织代码,提高可维护性和可扩展性,使得项目结构更加清晰。
本文将介绍MVC的基本概念、在iOS中的具体实现、优缺点、实践建议,以及其他常见的架构模式。
MVC的全称和基本概念:MVC即Model-View-Controller,分别代表模型、视图和控制器三个部分。
各个组件的职责:
在我们面试的过程中,MVC基本上是面试必问的基础性的问题。笔者总结了两点:MVC就是Controller拿Model的数据区更新View,同时Model和View之间是不互相通信的,它们之间的联系是通过Controller来桥接。
下图是斯坦福大学网上iOS公开课中的关于MVC的讲解,感觉总结的非常不错。
图1.MVC设计模式图
下面逐个分析下MVC中的每一个模块。
Model是数据模型的意思,在iOS的设计模式中,主要负责处理数据和业务逻辑。
Model的主要职责如下:
1.数据存储:Model负责存储应用程序的数据。数据可以来自本地存储、网络请求或其他外部数据源。
2.数据操作:Model包含操作数据的方法,例如创建、读取、更新和删除(CRUD)操作。
3.业务逻辑:Model还负责处理应用程序的业务逻辑,例如数据验证、计算和转换等。
4.数据通知:当数据发生变化时,Model可以通过通知或回调机制通知Controller,以便更新视图。
在实际的开发过程中,Model通常是一个或者多个类,这些类可以代表数据库中的表、网络请求的响应或其他数据结构
下面是一个简单的Model类示例,演示了如何定义和操作Model:
- // User.h
- #import <Foundation/Foundation.h>
-
- @interface User : NSObject
- @property (nonatomic, strong) NSString *name;
- @property (nonatomic, assign) NSInteger age;
-
- - (instancetype)initWithName:(NSString *)name age:(NSInteger)age;
- - (void)updateName:(NSString *)newName;
- @end
-
- // User.m
- #import "User.h"
-
- @implementation User
-
- - (instancetype)initWithName:(NSString *)name age:(NSInteger)age {
- self = [super init];
- if (self) {
- _name = name;
- _age = age;
- }
- return self;
- }
-
- - (void)updateName:(NSString *)newName {
- _name = newName;
- // 通知Controller数据已更新
- [[NSNotificationCenter defaultCenter] postNotificationName:@"UserUpdatedNotification" object:self];
- }
-
- @end

在这个示例中,User类是一个简单的Model类,包含用户的姓名和年龄。它还提供了一个方法来更新用户的姓名,并在更新后通过通知机制通知Controller。
Model通常不会直接与View通信,而是通过Controller进行中介。Controller负责监听Model的数据变化,并相应地更新View。
Model和Controller中的通信方式有以下几种方式:
Controller可以直接访问model的属性和方法。
Controller可以直接访问和操作Model的属性和方法,以获取或更新数据。这是最直接和常见的方式。
我们以下面的更新App版本号为例:
图1.更新app版本号
因为Controller直接持有Model,因此我们直接可以直接修改model数据:
#pragma mark -- AboutViewDelegate
- (void)didTapUpdateButton{
self.aboutModel.appVersion = [NSString stringWithFormat:@"%ld.%ld.%ld",[self generateRandomNumber:10],[self generateRandomNumber:99],[self generateRandomNumber:99]];
[self.aboutView configureWithModel:self.aboutModel];
}
- (NSInteger)generateRandomNumber:(NSInteger)random {
return arc4random_uniform(10) + 1; // 生成1到10之间的随机数
}
完整代码如下:
- #import "AboutViewController.h"
- #import "AboutView.h"
- #import "AboutModel.h"
- #import "Masonry.h"
-
- @interface AboutViewController ()<AboutViewDelegate>
-
- @property (nonatomic, strong) AboutView *aboutView;
- @property (nonatomic, strong) AboutModel *aboutModel;
-
- @end
-
- @implementation AboutViewController
-
- - (void)viewDidLoad {
- [super viewDidLoad];
- self.view.backgroundColor = [UIColor whiteColor];
- self.title = @"关于";
- [self setupModel];
- [self setupView];
- }
-
- - (void)setupModel {
- // 假设我们从某处获取了应用的名称和版本号
- NSString *appName = @"myApp";
- NSString *appVersion = @"1.0.0";
-
- self.aboutModel = [[AboutModel alloc] initWithAppName:appName appVersion:appVersion];
- }
-
- - (void)setupView {
- self.aboutView = [[AboutView alloc] initWithFrame:self.view.bounds];
- self.aboutView.delegate = self;
- [self.view addSubview:self.aboutView];
-
- [self.aboutView configureWithModel:self.aboutModel];
- }
-
- #pragma mark -- AboutViewDelegate
- - (void)didTapUpdateButton{
- self.aboutModel.appVersion = [NSString stringWithFormat:@"%ld.%ld.%ld",[self generateRandomNumber:10],[self generateRandomNumber:99],[self generateRandomNumber:99]];
- [self.aboutView configureWithModel:self.aboutModel];
-
- }
- - (NSInteger)generateRandomNumber:(NSInteger)random {
- return arc4random_uniform(10) + 1; // 生成1到10之间的随机数
- }
- @end

Model可以定义一个协议(protocol),Controller遵循这个协议并实现其方法。Model通过委托将数据变化通知给Controller,Controller则通过协议的方法来响应这些变化。
还以上面的demo为例,我们还可以把更新的方法传递到Controller,让controller去处理。
- #import "AboutViewController.h"
- #import "AboutView.h"
- #import "AboutModel.h"
- #import "Masonry.h"
-
- @interface AboutViewController ()<AboutViewDelegate,AboutModelDelegate>
-
- @property (nonatomic, strong) AboutView *aboutView;
- @property (nonatomic, strong) AboutModel *aboutModel;
-
- @end
-
- @implementation AboutViewController
-
- - (void)viewDidLoad {
- [super viewDidLoad];
- self.view.backgroundColor = [UIColor whiteColor];
- self.title = @"关于";
- [self setupModel];
- [self setupView];
- }
-
- - (void)setupModel {
- // 假设我们从某处获取了应用的名称和版本号
- NSString *appName = @"myApp";
- NSString *appVersion = @"1.0.0";
-
- self.aboutModel = [[AboutModel alloc] initWithAppName:appName appVersion:appVersion];
- self.aboutModel.delegate = self;
- }
-
- - (void)setupView {
- self.aboutView = [[AboutView alloc] initWithFrame:self.view.bounds];
- self.aboutView.delegate = self;
- [self.view addSubview:self.aboutView];
-
- [self.aboutView configureWithModel:self.aboutModel];
- }
-
- #pragma mark -- AboutViewDelegate
- - (void)didTapUpdateButton{
- NSLog(@"didTapUpdateButton");
- [self.aboutModel updateAppVersion:[NSString stringWithFormat:@"%ld.%ld.%ld",[self generateRandomNumber:10],[self generateRandomNumber:99],[self generateRandomNumber:99]]];
-
- }
- #pragma mark -- AboutModelDelegate
- - (void)didUpdateAppVersion:(NSString *)appVersion{
- NSLog(@"AboutModelDelegate");
- [self.aboutView configureWithModel:self.aboutModel];
- }
-
- - (NSInteger)generateRandomNumber:(NSInteger)random {
- return arc4random_uniform(10) + 1; // 生成1到10之间的随机数
- }
- @end

iOS的通知机制(NSNotificationCenter)允许在应用程序的不同部分之间发送消息。Controller可以监听特定的通知,以便在Model发出通知时执行相应的操作。
- // MyModel.h
- #import <Foundation/Foundation.h>
-
- @interface MyModel : NSObject
- @property (nonatomic, strong) NSString *data;
-
- - (void)updateData:(NSString *)newData;
- @end
-
- // MyModel.m
- #import "MyModel.h"
-
- @implementation MyModel
-
- - (void)updateData:(NSString *)newData {
- _data = newData;
- [[NSNotificationCenter defaultCenter] postNotificationName:@"DataUpdatedNotification" object:newData];
- }
-
- @end
-
- // MyViewController.m
- #import "MyViewController.h"
- #import "MyModel.h"
-
- @implementation MyViewController
-
- - (void)viewDidLoad {
- [super viewDidLoad];
-
- self.myModel = [[MyModel alloc] init];
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleDataUpdated:) name:@"DataUpdatedNotification" object:nil];
-
- [self.myModel updateData:@"New Data"];
- }
-
- - (void)handleDataUpdated:(NSNotification *)notification {
- NSString *updatedData = (NSString *)notification.object;
- NSLog(@"Model data updated: %@", updatedData);
- }
-
- - (void)dealloc {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- }
-
- @end

KVO是一种观察模式,允许对象监听其他对象属性的变化。Controller可以监听Model的属性变化,以便在属性发生变化时进行相应的处理。
- // MyModel.h
- #import <Foundation/Foundation.h>
-
- @interface MyModel : NSObject
- @property (nonatomic, strong) NSString *data;
- @end
-
- // MyModel.m
- #import "MyModel.h"
-
- @implementation MyModel
-
- - (instancetype)init {
- self = [super init];
- if (self) {
- _data = @"Hello, MVC!";
- }
- return self;
- }
-
- @end
-
- // MyViewController.m
- #import "MyViewController.h"
- #import "MyModel.h"
-
- @implementation MyViewController
-
- - (void)viewDidLoad {
- [super viewDidLoad];
-
- self.myModel = [[MyModel alloc] init];
- [self.myModel addObserver:self forKeyPath:@"data" options:NSKeyValueObservingOptionNew context:nil];
-
- self.myModel.data = @"Updated Data";
- }
-
- // 处理属性变化
- - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
- if ([keyPath isEqualToString:@"data"]) {
- NSLog(@"Model data changed: %@", change[NSKeyValueChangeNewKey]);
- }
- }
-
- - (void)dealloc {
- [self.myModel removeObserver:self forKeyPath:@"data"];
- }
-
- @end

view是视图的意思。在iOS MVC(Model-View-Controller)设计模式中,View 负责管理应用程序的用户界面(UI)部分。它是用户与应用程序进行交互的界面层,负责显示数据和响应用户操作。以下是对 View 的详细介绍:
在 iOS 应用程序中,View 的典型组件包括:UIView、UILabel、UIButton、UIImageView、UITableView等。
目标-动作模式是 iOS 中常用的一种通信方式,通常用于处理用户界面控件(如按钮、开关、滑块等)的事件。当用户与控件交互时,控件会向其指定的目标(通常是 Controller)发送一个动作消息。
// 在View中设置目标和动作
UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
[button setTitle:@"Press Me" forState:UIControlStateNormal];
[button addTarget:self action:@selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];// Controller 中实现动作方法
- (void)buttonPressed:(UIButton *)sender {
NSLog(@"Button was pressed");
}
托模式是一种常见的设计模式,允许一个对象向另一个对象通知发生的事件。在 iOS 中,许多 UIKit 组件都使用委托模式,例如 UITableView 和 UICollectionView。Controller 通常会作为 View 的委托对象,以便处理 View 的事件。
// 自定义View中的委托协议
@protocol CustomViewDelegate <NSObject>
- (void)customViewDidSomething:(UIView *)view;
@end@interface CustomView : UIView
@property (nonatomic, weak) id<CustomViewDelegate> delegate;
@end@implementation CustomView
- (void)doSomething {
[self.delegate customViewDidSomething:self];
}
@end// 在Controller中实现委托方法
@interface ViewController () <CustomViewDelegate>
@end@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
CustomView *customView = [[CustomView alloc] init];
customView.delegate = self;
[self.view addSubview:customView];
}- (void)customViewDidSomething:(UIView *)view {
NSLog(@"CustomView did something");
}
@end
通知中心(NSNotificationCenter)是一种广播机制,允许对象通过发布和观察通知进行通信。通知是一对多的通信机制,适用于需要向多个对象广播信息的情况。
// 发送通知
[[NSNotificationCenter defaultCenter] postNotificationName:@"CustomNotification" object:nil];// 观察通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleNotification:) name:@"CustomNotification" object:nil];// 处理通知的方法
- (void)handleNotification:(NSNotification *)notification {
NSLog(@"Received CustomNotification");
}// 移除观察者
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
KVC 和 KVO 是 Cocoa 提供的动态属性访问和观察机制。KVC 允许通过字符串键来访问对象的属性,KVO 允许对象观察其他对象属性的变化。
// Model类
@interface Person : NSObject
@property (nonatomic, strong) NSString *name;
@end@implementation Person
@end// Controller中使用KVO观察属性变化
@interface ViewController ()
@property (nonatomic, strong) Person *person;
@end@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.person = [[Person alloc] init];
[self.person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];
}// 实现观察者方法
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
if ([keyPath isEqualToString:@"name"]) {
NSLog(@"Person's name changed to %@", change[NSKeyValueChangeNewKey]);
}
}// 移除观察者
- (void)dealloc {
[self.person removeObserver:self forKeyPath:@"name"];
}
@end
Block 回调是一种轻量级的替代委托模式的方法。它允许在执行某些操作后,调用一个代码块(block)来处理结果。Block 回调简化了委托模式,不需要定义协议和委托对象。
// 自定义View类使用Block回调
@interface CustomView : UIView
@property (nonatomic, copy) void (^buttonPressedBlock)(void);
@end@implementation CustomView
- (instancetype)init {
self = [super init];
if (self) {
UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
[button setTitle:@"Press Me" forState:UIControlStateNormal];
[button addTarget:self action:@selector(buttonPressed) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:button];
}
return self;
}- (void)buttonPressed {
if (self.buttonPressedBlock) {
self.buttonPressedBlock();
}
}
@end// 在Controller中设置Block回调
@interface ViewController ()
@end@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
CustomView *customView = [[CustomView alloc] init];
customView.buttonPressedBlock = ^{
NSLog(@"Button was pressed in CustomView");
};
[self.view addSubview:customView];
}
@end
在 iOS 的 MVC(Model-View-Controller)设计模式中,Controller 是连接 Model 和 View 的中介,负责处理应用程序的业务逻辑和用户交互。Controller 的主要职责是从 Model 中获取数据,更新 View,并响应用户输入。以下是对 Controller 的详细介绍:
1.管理视图:
Controller 负责创建和配置 View,并将 Model 中的数据传递给 View 进行显示。当 Model 的数据发生变化时,Controller 也会通知 View 进行相应的更新。
2.处理用户输入:
Controller 响应用户在 View 上的各种操作,例如点击按钮、滑动手势等。它会根据用户的输入更新 Model,并通过 View 来反映这些变化。
3.业务逻辑:
Controller 包含应用程序的业务逻辑和数据处理逻辑。它从 Model 获取数据、处理数据,并将处理结果传递给 View。
3.中介作用:
Controller 充当 Model 和 View 之间的中介。它负责协调这两者之间的通信,使得 View 不直接与 Model 交互,从而保持两者的解耦。
在 iOS 开发中,UIViewController 是 Controller 的基类。每个 UIViewController 都管理一个 UIView,并与该视图相关联的 Model 进行交互。
Controller和Model以及View之间的通信可以看上面的章节。
1.易于测试和维护
各个组件独立,便于单独测试和维护。
2.代码复用性强
View和Model可以在不同的Controller中重复使用,提高代码复用性。
1.可能导致Controller过于臃肿
在处理复杂逻辑时,Controller可能变得过于庞大,难以维护。
2.View和Controller之间的耦合度较
由于Controller直接管理View,导致二者耦合度较高,不利于独立开发和测试。
3.复杂项目中的可扩展性问题
在大型项目中,MVC可能难以满足复杂需求,需要引入其他设计模式进行补充。
1.如何避免Controller臃肿
使用Helper类或Extensions分担部分逻辑。
将业务逻辑移到Model层,尽量保持Controller的简洁。
2.减少View和Controller的耦合
使用协议和委托模式来解耦。
利用通知和KVO(Key-Value Observing)机制实现低耦合的数据传递。
3.代码组织和文件结构的最佳实践:
将Model、View、Controller分别放在不同的文件夹中。
使用命名空间或模块化方式组织代码。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。