[英]How to Pass Values between Multiple View Controllers using Delegate / Protocol
[英]How to pass values between 2 View Controllers without protocol?
我有两个视图控制器,分别称为viewA
和ViewB
ViewA
ViewB
, ViewB
,菜单弹出 现在,用户触摸一个IBAction
按钮,以编程方式只需要:
BOOL
的值,将其myBOOL
为YES
ViewB
myBOOL
变量的当前状态为YES
传递回ViewA
我已经声明了相同的BOOL
,set属性,在两个View上合成,但是根据我的NSLog
在解雇ViewB
并加载备份ViewA
,它恢复为NO
所以我知道我要切线了,我只想知道您是否可以在两个控制器之间发送BOOL
的值,如果可以,请给我一个例子...搜索发现协议和委托示例与NSString
,当我尝试使用BOOL
我陷入了一个导入循环,但是,我读到它有可能使全局BOOL
成为一个糟糕的设计,尽管如此,我现在只需要克服这个问题即可。 。
关于这个主题的问题实际上应该更多地集中在NSNotificationCenter
而不是NSUserDefaults
,请注意,这两个都是单例。
NSUserDefaults
:
此类的目的不是在类之间传递变量。 目的是存储用户的默认值。 (即首选项,设置等)。
NSNotificationCenter
:
该类非常方便,并且具有许多不同的用途,其中之一是广播变量以供任何类接收。 接收类称为观察者。 此模式称为观察者模式 。
注意: NSUserDefaults
方法的优点是允许您在初始化其他类之前设置变量,并且可以随时对其进行检索。 但是,这确实很草率(IMHO),并且被认为是不好的做法。
NSNotificationCenter
上的快速和肮脏代码示例:
// upon initializing the class that wants to observe the changes, we add it as an observer.
// So, somewhere in the A.m, upon being initialized (init, maybe?).
- (id)init {
if (self = [super init]) {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(calledUponNotif:)
name:@"MyObserveKey"
object:nil];
}
return self;
}
// the selector should look something like this:
- (void)calledUponNotif:(NSNotification *)notif {
id sentVar = [notif object];
}
// Somewhere in the B.m
[[NSNotificationCenter defaultCenter] postNotificationName:@"MyObserveKey"
object:varToSend];
另一个注意事项 :调用postNotification方法后,另一个类中已注册的选择器将被同步调用,因此您不必担心。
有独立于视图的值保持工具。 您可以使用:
[[NSUserDefaults standardUserDefaults]setObject:<#(id)#> forKey:<#(NSString *)#>]
例如,您在A视图中输入字符串或数据,则可以将它们存储在上述变量中。 然后,在B视图中,可以通过以下代码使用它们:
[[NSUserDefaults standardUserDefaults]objectOrKey:<#(NSString *)#>]
这些是使用以下示例的NSUserDefaults
数据的示例:
查看A:
- (void)textFieldDidEndEditing:(UITextField *)sender
{
if (sender == homepage) {
[[NSUserDefaults standardUserDefaults]
setURL:[NSURL URLWithString:homepage.text] forKey:Ever5secHomepagePrefKey];
if( [homepage canResignFirstResponder] ) {
[homepage resignFirstResponder];
}
} else if (sender == userId) {
[[NSUserDefaults standardUserDefaults]
setObject:userId.text forKey:Ever5secUserIdPrefKey];
objectForKey:Ever5secUserIdPrefKey]);
if( [userId canResignFirstResponder] ) {
[userId resignFirstResponder];
}
} else if (sender == password) {
[[NSUserDefaults standardUserDefaults]
setObject:password.text forKey:Ever5secPasswordPrefKey];
if( [password canResignFirstResponder] ) {
[password resignFirstResponder];
}
}
}
查看B:
userId.text = [[NSUserDefaults standardUserDefaults]
objectForKey:Ever5secUserIdPrefKey];
password.text = [[NSUserDefaults standardUserDefaults]
objectForKey:Ever5secPasswordPrefKey];
homepage.text = [[[NSUserDefaults standardUserDefaults]
URLForKey:Ever5secHomepagePrefKey]
description];
这不是一个好的封装答案,但是如果不能使用协议或委托,我认为它不会具有很好的封装。
您还可以创建一个全局变量,您可以在一个视图控制器中进行设置,而在另一个视图控制器中进行访问。
ViewControllerOne.h
extern NSString *globalVariable;
@interface ViewControllerOne
@end
ViewControllerOne.m
#import "ViewControllerOne.h"
@implementation ViewControllerOne
NSString *globalVariables = @"Some String in the variable to access in second controller";
@end
ViewControllerTwo.m
#import "ViewControllerTwo.h"
#import "ViewControllerOne.h"
@implemetation ViewControllerTwo
- (void)viewDidLoad
{
NSLog("%@", globalVariables);
}
@end
这将打印到控制台中
****CONSOLE****
Some String in the variable to access in second controller
您不需要使用NSNotificationCenter,NSUserDefaults或全局变量。
只要视图控制器是相关的(并且考虑到OP的问题,它们的确似乎是相关的),您就可以简单地将视图控制器设置为相互保持引用(当然其中一个引用很弱)避免“保留”或“强引用”循环)。 然后,每个视图控制器都可以根据需要在另一个视图控制器上设置属性。 示例如下...
注意:此概念对任何两个相关的视图控制器均有效。 但是,以下代码假定:
FirstViewController.h
@interface FirstViewController : UIViewController
/* Hold the boolean value (or whatever value should be
set by the second view controller) in a publicly
visible property */
@property (nonatomic, assign) BOOL someBooleanValue;
/* Provide a method for the second view controller to
request the first view controller to dismiss it */
- (void)dismissSecondViewController;
@end
FirstViewController.m
#import "FirstViewController.h"
#import "SecondViewController.h"
@implementation FirstViewController
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
/* Get the reference to the second view controller and set
the appropriate property so that the secondViewController
now has a way of talking to the firstViewController */
SecondViewController *vc = [segue destinationViewController];
vc.firstViewController = self;
}
- (void)dismissSecondViewController
{
// Hide the secondViewController and print out the boolean value
[self.navigationController popViewControllerAnimated:YES];
NSLog(@"The value of self.someBooleanValue is %s", self.someBooleanValue ? "YES" : "NO");
}
@end
SecondViewController.h
#import "FirstViewController.h"
@interface SecondViewController : UIViewController
// Create a 'weak' property to hold a reference to the firstViewController
@property (nonatomic, weak) FirstViewController *firstViewController;
@end
SecondViewController.m
@implementation SecondViewController
/* When required (in this case, when a button is pressed),
set the property in the first view controller and ask the
firstViewController to dismiss the secondViewController */
- (IBAction)buttonPressed:(id)sender {
self.firstViewController.someBooleanValue = YES;
[self.firstViewController dismissSecondViewController];
}
@end
当然,处理此类内部viewController通信的最正确方法是使用协议/代理/数据源,以便SecondViewController不需要知道其父对象/所有者对象的细节。 但是,有时候为了证明这一概念而构建这样的解决方案会更快/更简单。 然后,如果一切都很好并且代码值得保留,请重构以使用协议。
如果视图控制器彼此之间不应该互相了解,则可能有必要使用NSNotificationCenter。 不要在视图控制器之间使用全局变量或NSUserDefaults进行通信。
有两个选项可用于在不同的视图控制器中存储和检索数据。
1) NSUserDefaults
是用于存储数据和在任何其他视图控制器中访问的最佳选项。
NSUserDefaults
类提供了用于访问常见类型(例如float, double, integer, Boolean
便捷方法。
默认对象必须是属性列表 ,即NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary
的实例(或用于集合的实例的组合)。
这是用于存储和检索数据的非常简单且最佳的方法。
如果您想阅读有关NSUserDefaults
,我在这里共享文档。 [NsuserDefaults文档。] [1]
2)当您希望属性可以在类或其他视图控制器之外访问时,可以创建属性。
以这种方式创建属性。 @property (nonatomic, retain) NSArray *arrayData;
然后您也可以在其他视图控制器中使用此数组值。
属性替换对象的访问器方法。
有两个选项可用于在不同的视图控制器中存储和检索数据。
1) NSUserDefaults
是用于存储数据和在任何其他视图控制器中访问的最佳选项。
NSUserDefaults
类提供了用于访问常见类型(例如float, double, integer, Boolean
便捷方法。
默认对象必须是属性列表 ,即NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary
的实例(或用于集合的实例的组合)。
这是用于存储和检索数据的非常简单且最佳的方法。
如果您想阅读有关NSUserDefaults
,我在这里共享文档。 NsuserDefaults文档。
2)当您希望属性可以在类或其他视图控制器之外访问时,可以创建属性。
以这种方式创建属性。 @property (nonatomic, retain) NSArray *arrayData;
然后您也可以在其他视图控制器中使用此数组值。
属性替换对象的访问器方法。
您可以在这里看到我的答案。 将值从一个视图控制器传递给另一个
我认为通过以下方式使用块的强大功能的最佳方法。
在ViewB.h中
typedef void (^CompletionHandler)(BOOL myBool);
@interface ViewB : UIViewController {
CompletionHandler completionHandler;
}
- (void)dismissHandler:(CompletionHandler)handler;
在ViewB.m中
- (void)dismissHandler:(CompletionHandler)handler {
completionHandler = handler;
}
- (IBAction)dismiss:(id)sender {
completionHandler (YES); // your yes no logic here
}
在ViewA.m
- (IBAction)showPopup:(id)sender {
ViewB *vc = [[ViewB alloc] init];
[self.view addSubview:vc.view];
[vc dismissHandler:^(BOOL myBool) {
if (myBool) {
//Do your work;
}
}];
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.