0

我有两个视图控制器,调用它们viewAViewB

  • 所有动作都发生在主视图中 -ViewA
  • 按下菜单按钮,弹出ViewB,一切正常,菜单出现

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

  1. 改变 a 的值,BOOL调用它myBOOLYES
  2. 解雇ViewB
  3. myBOOL变量的当前状态传递YESViewA

我已经BOOL在两个视图上声明了相同的 set 属性,但是根据我NSLog的解雇ViewB和加载备份ViewA,它恢复为NO

所以我知道我正在切线,我只想知道你是否可以BOOL在两个控制器之间发送 a 的值,如果可以,请给我看一个例子......因为搜索已经找到了带有NSString' 的协议和委托示例s,当我尝试使用 a 时,BOOL我陷入了一个导入循环,但是我已经读到它可以制作一个 global BOOL,尽管它是糟糕的设计,但我现在只需要克服这个障碍。

4

7 回答 7

7

关于这个主题的问题应该更多地关注NSNotificationCenter而不是NSUserDefaults,请注意两者都是单例。

NSUserDefaults

此类的目的不是在类之间传递变量。它的目的是存储用户的默认值。(即偏好、设置等)。

NSNotificationCenter

这个类非常方便,并且有许多不同的用途,其中之一就是广播一个变量让任何类接收。接收类称为观察者。这种模式被称为观察者模式

注意:NSUserDefaults方法的优点是允许您在初始化其他类之前设置变量,并且可以随时检索。然而,这真的很草率(恕我直言)并且被认为是不好的做法。


快速而肮脏的代码示例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 方法后,其他类中注册的选择器会被同步调用,所以你不必担心。

于 2012-08-12T08:47:42.190 回答
3

有独立于视图的保值工具。您可以使用:

[[NSUserDefaults standardUserDefaults]setObject:<#(id)#> forKey:<#(NSString *)#>]

例如,您在 A 视图中输入字符串或数据,您可以将它们存储在上述变量中​​。然后,在 B 视图中,您可以通过以下代码使用它们:

 [[NSUserDefaults standardUserDefaults]objectOrKey:<#(NSString *)#>]

这些是NSUserDefaults使用以下数据的示例:

ss

观点一:

- (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];
于 2012-08-12T00:07:36.830 回答
3

这不是一个好的封装答案,但由于无法使用协议或委托,我不相信它会有好的封装。

您还可以创建一个全局变量,您可以在一个视图控制器中设置该变量并在另一个视图控制器中访问。

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
于 2012-08-12T08:28:51.080 回答
1

你不需要使用 NSNotificationCenter、NSUserDefaults 或全局变量。

只要视图控制器是相关的(并且查看 OP 的问题,它们肯定是相关的),您可以简单地设置视图控制器以保持对彼此的引用(其中一个引用当然是弱的,以便避免“保留”或“强参考”循环)。然后每个视图控制器可以根据需要在另一个视图控制器上设置属性。示例如下...

注意:这个概念适用于任何两个相关的视图控制器。但是,以下代码假定:

  • 有问题的视图控制器通过导航控制器相关联,第二个视图控制器通过 push segue 连接到第一个视图控制器。
  • 正在使用 iOS 5.0 或更高版本(因为它使用情节提要)。

第一视图控制器.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

第一视图控制器.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

第二视图控制器.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 在视图控制器之间进行通信。

于 2013-02-08T14:07:33.293 回答
1

在不同的视图控制器中存储和检索数据有两个选项。

1)NSUserDefaults是在任何其他视图控制器中存储数据和访问的最佳选择。

该类NSUserDefaults提供了方便的方法来访问常见类型,例如float, double, integer, Boolean.

默认对象必须是属性列表,即(或集合的实例组合)的实例:NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary

这是存储和检索数据的非常简单和最佳的方法。

如果你想阅读NSUserDefaults,我在这里分享文档。[NsuserDefaults 文档。][1]

2) 当您希望它们可以在类或其他视图控制器之外访问时,您将创建属性。

以这种方式创建属性。@property (nonatomic, retain) NSArray *arrayData;然后你也可以在其他视图控制器中使用这个数组值。

属性替换了对象的访问器方法。

于 2013-02-08T14:11:57.187 回答
1

在不同的视图控制器中存储和检索数据有两个选项。

1)NSUserDefaults是在任何其他视图控制器中存储数据和访问的最佳选择。

该类NSUserDefaults提供了方便的方法来访问常见类型,例如float, double, integer, Boolean.

默认对象必须是属性列表,即(或集合的实例组合)的实例:NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary

这是存储和检索数据的非常简单和最佳的方法。

如果你想阅读NSUserDefaults,我在这里分享文档。 NsuserDefaults 文档。

2) 当您希望它们可以在类或其他视图控制器之外访问时,您将创建属性。

以这种方式创建属性。@property (nonatomic, retain) NSArray *arrayData;然后你也可以在其他视图控制器中使用这个数组值。

属性替换了对象的访问器方法。

你可以在这里看到我的答案。将值从一个视图控制器传递到另一个视图控制器

于 2013-02-08T14:15:58.577 回答
0

我认为以以下方式使用块的强大功能的最佳方法。

在视图B.h

typedef void (^CompletionHandler)(BOOL myBool);
@interface ViewB : UIViewController {
    CompletionHandler completionHandler;
}
- (void)dismissHandler:(CompletionHandler)handler;

在视图B.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;
        }
    }];
}
于 2013-02-25T10:18:43.263 回答