目录
- 前言
- 属性传值
- 步骤(主要涉及到属性的声明和赋值)
- 代码示例
- 协议(Delegation)传值
- 步骤(涉及到定义协议、实现协议函数等)
- 代码示例
- 单例(Singleton )传值
- 步骤(主要涉及到单例模式的创建)
- 代码示例
- 通过通知(NSNotification)传值
- 步骤(主要涉及到通知的发布和监听)
- 代码示例
- 关于NSNotificationCenter
- NSNotificationCenter主要方法:
- 代码示例:
- 总结
前言
在iOS开发中,多界面传值是一个常见的问题。多界面传值的方法有很多,本篇博客主要介绍属性传值, 代理传值(即协议传值),单例传值,通知传值。
关于另外两个多界面传值方法——闭包(block)传值和KVO(Key-Value Observing )传值,在后续的学习中,我会继续记录我的理解。
属性传值
属性传值是一种简单而直观的方式,用于在不同界面之间传递数据。属性传值最大的特点就是正向传值,即A页面传值给B页面。需要在B中声明一个属性(之所以在B.h中定义,是因为在B.h中声明的属性,在A的文件里新创建B视图控制器后也可以访问),因为要将A中的值传给B,所以在A中定义一个B视图控制器类型的页面,然后在推入目标界面的控制器A(传递数据的界面)中将所需的值赋给新定义页面的属性。这样,目标界面的控制器B就可以访问这个属性的值了。这种方式适用于两个界面之间的直接数据传递,不涉及第三个界面。
步骤(主要涉及到属性的声明和赋值)
1.在目标视图控制器(接收数据的视图控制器)中定义一个公开的属性,用于接收数据。
2.在源视图控制器(传递数据的视图控制器)中设置目标视图控制器的这个属性。
代码示例
// 在目标视图控制器中定义属性(.h文件)
@interface TargetViewController : UIViewController
@property (nonatomic, strong) NSString *receivedData;
@end
//记得引用目标视图控制器的.h文件
// 在源视图控制器中设置属性(.m文件)
TargetViewController *targetVC = [[TargetViewController alloc] init];
targetVC.receivedData = @"Hello, World!";
[self.navigationController pushViewController:targetVC animated:YES];
属性传值更适合于同一组件内的数据传递,例如在一个视图控制器内部的不同视图之间传递数据。
协议(Delegation)传值
协议传值是一种反向传值的方式,即B页面(发送数据页面,即源视图控制器)传值给A页面(接收数据页面,即目标视图控制器)。在B页面,定义一个代理协议,定义协议实现函数,并定义一个属性,该属性需要定义一个协议(代理)对象,来记录需要传递的值,注意为id类型(实例类型)。在B页面的合适时机调用协议实现函数(即代理对象会执行协议函数,从而达到改变代理对象本身属性的目的)。然后令接收数据的页面A在.h文件遵循B里的协议,并在A的.m文件内实现该协议函数,从而完成B向A的反向传值。
步骤(涉及到定义协议、实现协议函数等)
1.在源视图控制器中定义一个协议(delegate),并声明相应的方法,然后声明一个代理对象。
2.在目标视图控制器中遵循协议,实现该协议的方法,并设置目标视图控制器的代理。
代码示例
// 在源视图控制器B(发送数据)中定义协议
@protocol TargetViewControllerDelegate <NSObject>
//声明相应的方法(需要传什么就设置成什么类型)
- (void)didReceiveData:(NSString *)data;
@end
@interface TargetViewController : UIViewController
//设置代理对象
@property (nonatomic, weak) id<TargetViewControllerDelegate> delegate;
@end
// 在目标视图控制器A(接收数据)中遵循协议(记得引用源视图控制器的.h文件)
@interface SourceViewController : UIViewController <TargetViewControllerDelegate>
@end
@implementation SourceViewController
//实现协议方法
- (void)didReceiveData:(NSString *)data {
NSLog(@"Received data: %@", data);
}
@end
协议传值适合用于不同组件间灵活的数据交互,特别是当某些数据需要从子组件向父组件传递时。
单例(Singleton )传值
单例传值是一种更为高级的数据传递方式,适用于在多个界面之间传递数据。通过创建一个单例对象,在整个应用生命周期内保持其唯一实例,并在任何界面中访问它。你可以在单例对象中存储和更新数据,然后在需要的地方获取这些数据。这种方式的优势在于可以在多个界面之间共享数据,而无需在每个界面之间传递数据。
“在整个应用生命周期内保持其唯一实例”意味着在应用程序运行的整个时间里,特定的类或对象只会存在一个实例,并且这个实例在整个应用中是唯一的、全局可访问的。简单来说,就是确保在应用的启动到终止期间,这个类的实例只有一个,而且这个实例可以被整个应用程序中的所有代码共享和使用。
- 唯一实例
唯一实例(Single Instance)指的是一个类在应用生命周期内只有一个对象实例。即便在不同的地方或多个线程中请求这个类的实例,也只会返回同一个对象。- 应用生命周期
应用生命周期指的是从应用程序启动到退出的整个过程。在这个过程中,应用程序会经历启动、运行、后台、终止等不同状态,但唯一实例的对象应该在这整个过程中保持不变。- 全局访问
通过单例模式创建的唯一实例在应用程序的任何地方都可以被访问。这样,所有需要访问该对象的部分都能够引用同一个实例,从而保证数据的一致性和操作的同步。
步骤(主要涉及到单例模式的创建)
1.创建一个 Singleton 类,用于存储需要传递的数据。
2.在源视图控制器中设置数据,在目标视图控制器中获取数据。
代码示例
// Singleton 类
@interface DataStore : NSObject
//需要保存或传递什么数据类型,就声明成什么类型
@property (nonatomic, strong) NSString *sharedData;
+ (instancetype)sharedInstance;
@end
@implementation DataStore
+ (instancetype)sharedInstance {
// 静态变量,存储单例实例
static DataStore *sharedInstance = nil;
// 用于确保代码块只执行一次的标记
static dispatch_once_t onceToken;
// 确保仅创建一个实例
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
@end
// 在源视图控制器中设置数据(记得引用单例的.h文件)
[DataStore sharedInstance].sharedData = @"Hello, World!";
// 在目标视图控制器中获取数据(记得引用单例的.h文件)
NSString *data = [DataStore sharedInstance].sharedData;
NSLog(@"Received data: %@", data);
通过通知(NSNotification)传值
除了以上三种方式,还可以使用通知中心(Notification Center)进行多界面传值。通知中心是iOS提供的一个事件通知机制,可以用来在不同的界面之间传递数据。通过创建一个通知中心,并在需要传递数据的界面中发送通知,可以在不直接引用其他界面的情况下传递数据。你可以将要传输的数据作为通知的一部分发送出去,然后在接收通知的界面中处理这些数据。这种方式适用于在不同界面之间传递少量数据或者执行一些异步操作。
步骤(主要涉及到通知的发布和监听)
1.在需要发送数据的视图控制器中发送通知。
2.在接收数据的视图控制器中监听该通知。
代码示例
// 源视图控制器发送通知
[[NSNotificationCenter defaultCenter] postNotificationName:@"DataNotification" object:@"Hello, World!"];
// 目标视图控制器监听通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleNotification:) name:@"DataNotification" object:nil];
- (void)handleNotification:(NSNotification *)notification {
NSString *data = notification.object;
NSLog(@"Received data: %@", data);
}
关于NSNotificationCenter
NSNotificationCenter 提供了一种机制来发布和接收通知。通知是一个广播机制,允许应用程序的不同部分在不直接知道彼此的情况下交换信息。NSNotificationCenter 是一个中心化的系统,用于处理通知的发布和接收。
NSNotificationCenter主要方法:
defaultCenter:获取 NSNotificationCenter 的共享实例。
发布通知:通过调用 postNotificationName:object:userInfo: 方法,发送一个通知到 NSNotificationCenter。
注册观察者:通过调用 addObserver:selector:name:object: 方法,注册一个观察者来接收特定通知。
移除观察者:通过调用 removeObserver: 方法,可以移除一个观察者,停止接收通知。
代码示例:
发布通知(一般在源视图控制器里):
// 发布通知(一般在源视图控制器里使用)
[[NSNotificationCenter defaultCenter] postNotificationName:@"MyNotification" object:nil userInfo:@{@"Key": @"Value"}];
postNotificationName::通知的名称
object::发送通知的对象(通常可以是 nil)
userInfo::一个字典,可以用来附加额外的信息(可以是 nil)
注册观察者(一般在目标视图控制器里):
// 注册观察者(一般在目标视图控制器里使用)
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleNotification:) name:@"MyNotification" object:nil];
addObserver::观察者对象(通常是 self)
selector::观察者接收到通知时调用的方法(在后面要进行该方法的实现)
name::要接收的通知的名称
object::要观察的对象(通常可以是 nil,表示接收所有该名称的通知)
移除观察者(在不再需要接收通知时,移除观察者):
// 移除观察者
[[NSNotificationCenter defaultCenter] removeObserver:self];
removeObserver: 你要移除的观察者对象
为什么需要移除观察者?
避免内存泄漏:如果对象在被释放后仍然注册为观察者,它会继续接收通知,这可能导致尝试访问已经释放的内存,从而引发崩溃。
防止异常:如果观察者对象已经被销毁,但通知系统仍尝试发送通知给它,可能会导致运行时异常。
资源管理:移除不再需要的观察者可以减少系统资源的消耗,避免不必要的消息传递。
移除观察者的情况:
视图控制器的释放:在视图控制器的 dealloc 方法中,通常会移除该视图控制器作为通知的观察者,以避免在视图控制器被销毁后,仍然收到通知。
临时注册:如果观察者对象只是临时使用的,确保在适当的时候移除它,以防止继续接收不需要的通知。
对象生命周期结束:当对象不再需要接收通知时,例如在任务完成或对象状态变化时,应该移除观察者。
总结
属性传值适用于两个界面之间的直接数据传递;
协议传值适合用于不同组件间灵活的数据交互;
单例传值适用于在多个界面之间共享数据;
通过通知中心进行传值则适用于在不同界面之间传递少量数据或者执行异步操作;
iOS多界面传值有多种方式可供选择在实践中,根据具体情况选择合适的方式可以有效地解决多界面数据传递的问题,提高代码的效率和可维护性,提升应用的用户体验和性能。此外,为了保持应用的性能和稳定性,需要注意避免过度使用数据传递。过度依赖数据传递可能导致代码的耦合度增加,不利于维护和扩展。