繁体   English   中英

如何在没有协议的情况下在2个View Controller之间传递值?

[英]How to pass values between 2 View Controllers without protocol?

我有两个视图控制器,分别称为viewAViewB

  • 所有操作都在主视图中发生ViewA
  • 点击一个菜单按钮,弹出ViewBViewB ,菜单弹出

现在,用户触摸一个IBAction按钮,以编程方式只需要:

  1. 更改BOOL的值,将其myBOOLYES
  2. 关闭ViewB
  3. 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数据的示例:

ss

查看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的问题,它们的确似乎是相关的),您就可以简单地将视图控制器设置为相互保持引用(当然其中一个引用很弱)避免“保留”或“强引用”循环)。 然后,每个视图控制器都可以根据需要在另一个视图控制器上设置属性。 示例如下...

注意:此概念对任何两个相关的视图控制器均有效。 但是,以下代码假定:

  • 所讨论的视图控制器通过导航控制器关联,第二个视图控制器通过推键连接到第一个视图控制器。
  • 使用的是iOS 5.0或更高版本(因为使用了故事板)。

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM