无法在视图之间读取NSUserDefaults数据

Sam*_*Sam 3 iphone cocoa-touch objective-c

免责声明:主要菜鸟

我正在编写一个算术闪存卡应用程序作为学习项目.我有一个UITabViewController,底部的标签栏可以在几个不同的视图之间切换.一切正常,直到我尝试在Settings视图控制器中设置NSUserDefault布尔值并尝试在Flashcards视图控制器中读取这些值.

设置视图有一个开关,用于启用/禁用每个操作符(加法,减法等),如果启用了此类操作,则闪卡视图应随机显示闪存卡.

我相信我的错误是我不理解数据封装,对象等的关键概念.我很感激任何帮助.

这是"设置"视图控制器.我甚至不确定如何将代码放入此论坛,所以这可能是一个可笑的时刻......这里是:

//  settings_flashcards.h

#import <UIKit/UIKit.h>
@interface settings_flashcards : UIViewController {
UISwitch *additionSwitch;
UISwitch *subtractionSwitch;
UISwitch *multiplicationSwitch;
UISwitch *divisionSwitch;
}

@property (nonatomic,retain) IBOutlet UISwitch *additionSwitch;
@property (nonatomic,retain) IBOutlet UISwitch *subtractionSwitch;
@property (nonatomic,retain) IBOutlet UISwitch *multiplicationSwitch;
@property (nonatomic,retain) IBOutlet UISwitch *divisionSwitch;

@end
Run Code Online (Sandbox Code Playgroud)

和...

/  settings_flashcards.m

#import "settings_flashcards.h"

@implementation settings_flashcards

@synthesize additionSwitch;
@synthesize subtractionSwitch;
@synthesize multiplicationSwitch;
@synthesize divisionSwitch;

- (void)viewDidLoad {

[additionSwitch addTarget:self action:@selector(additionSwitchFlipped) forControlEvents:UIControlEventValueChanged];
[subtractionSwitch addTarget:self action:@selector(subtractionSwitchFlipped) forControlEvents:UIControlEventValueChanged];
[multiplicationSwitch addTarget:self action:@selector(multiplicationSwitchFlipped) forControlEvents:UIControlEventValueChanged];
[divisionSwitch addTarget:self action:@selector(divisionSwitchFlipped) forControlEvents:UIControlEventValueChanged];
[super viewDidLoad];
}

-(void) additionSwitchFlipped {
if (additionSwitch.on) {
    [[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:@"additionKey"];
}else {
    [[NSUserDefaults standardUserDefaults] setBool:FALSE forKey:@"additionKey"];
}
}

-(void) subtractionSwitchFlipped {
if (subtractionSwitch.on) {
    [[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:@"subtractionKey"];  
}else {
    [[NSUserDefaults standardUserDefaults] setBool:FALSE forKey:@"subtractionKey"]; 
}
}

-(void) multiplicationSwitchFlipped {
if (multiplicationSwitch.on) {
    [[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:@"multiplicationKey"];   
}else {
    [[NSUserDefaults standardUserDefaults] setBool:FALSE forKey:@"multiplicationKey"];  
}

}

-(void) divisionSwitchFlipped {
if (divisionSwitch.on) {
    [[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:@"divisionKey"]; 
}else {
    [[NSUserDefaults standardUserDefaults] setBool:FALSE forKey:@"divisionKey"];    
}
}
Run Code Online (Sandbox Code Playgroud)

这是Flashcards视图......

//  flashcardsViewController.h

#import <UIKit/UIKit.h>

@interface flashcardsViewController : UIViewController <UIActionSheetDelegate>{

UILabel *firstNumberLabel;
UILabel *secondNumberLabel;
UILabel *answerNumberLabel;
UILabel *operatorLabel;

BOOL additionIsEnabled;
BOOL subtractionIsEnabled;
BOOL multiplicationIsEnabled;
BOOL divisionIsEnabled;
}

@property (nonatomic,retain) IBOutlet UILabel *firstNumberLabel;
@property (nonatomic,retain) IBOutlet UILabel *secondNumberLabel;
@property (nonatomic,retain) IBOutlet UILabel *answerNumberLabel;
@property (nonatomic,retain) IBOutlet UILabel *operatorLabel;

-(void) buttonClicked:(id)sender;

@end
Run Code Online (Sandbox Code Playgroud)

和...

//  flashcardsViewController.m

#import "flashcardsViewController.h"

@implementation flashcardsViewController

@synthesize firstNumberLabel;
@synthesize secondNumberLabel;
@synthesize answerNumberLabel;
@synthesize operatorLabel;

- (void)viewDidLoad {

srand(time(0)); //seed random

//the following should assign the keys if they don't exist  
if (![[NSUserDefaults standardUserDefaults] boolForKey:@"additionKey"]){
    [[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:@"additionKey"];
}   


if (![[NSUserDefaults standardUserDefaults] boolForKey:@"subtractionKey"]) {
    [[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:@"subtractionKey"];
}

if (![[NSUserDefaults standardUserDefaults] boolForKey:@"multiplicationKey"]) {
    [[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:@"multiplicationKey"];

}

if (![[NSUserDefaults standardUserDefaults] boolForKey:@"divisionKey"]) {
    [[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:@"divisionKey"];
}

//the following should assign each BOOL variable based on the key
additionIsEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:@"additionKey"];
subtractionIsEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:@"subtractionKey"];
multiplicationIsEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:@"multiplicationKey"];
divisionIsEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:@"divisionKey"];
[super viewDidLoad];
}

-(void) buttonClicked:(id)sender{

int a = rand() %  4;// random number generator (number to enter loop)   

if ( additionIsEnabled || subtractionIsEnabled || multiplicationIsEnabled || divisionIsEnabled) {
    while (a < 5) {
        switch (a) {
            case 0:
                if (additionIsEnabled == TRUE){
                    int x = rand() % 11 + 1;
                    int y = rand() %11 + 1;
                    firstNumberLabel.text = [[NSString alloc]initWithFormat: @"%i",x];
                    secondNumberLabel.text = [[NSString alloc]initWithFormat: @"%i",y];
                    answerNumberLabel.text = [[NSString alloc]initWithFormat: @"%i",(x+y)];
                    operatorLabel.text = [[NSString alloc]initWithFormat: @"+"];
                    a = 5;
                }
                else a++;
                break;
            case 1:
                if (subtractionIsEnabled == TRUE){
                    int x = rand() % 19 + 1;
                    int y = rand() %11 + 1;
                    firstNumberLabel.text = [[NSString alloc]initWithFormat: @"%i",x];
                    secondNumberLabel.text = [[NSString alloc]initWithFormat: @"%i",y];
                    answerNumberLabel.text = [[NSString alloc]initWithFormat: @"%i",(x-y) ];
                    operatorLabel.text = [[NSString alloc]initWithFormat: @"-"];
                    a = 5;
                }
                else a++;
                break;
            case 2:
                if (multiplicationIsEnabled == TRUE){
                    int x = rand() % 11 + 1;
                    int y = rand() %11 + 1;
                    firstNumberLabel.text = [[NSString alloc]initWithFormat: @"%i",x];
                    secondNumberLabel.text = [[NSString alloc]initWithFormat: @"%i",y];
                    answerNumberLabel.text = [[NSString alloc]initWithFormat: @"%i",(x*y)];
                    operatorLabel.text = [[NSString alloc]initWithFormat: @"×"];
                    a = 5;
                }
                else a++;
                break;
            case 3:
                if (divisionIsEnabled == TRUE){
                    int x = rand() % 11 + 1;
                    int y = rand() % 11 + 1;
                    firstNumberLabel.text = [[NSString alloc]initWithFormat: @"%i",(x*y)];
                    secondNumberLabel.text = [[NSString alloc]initWithFormat: @"%i",y];
                    answerNumberLabel.text = [[NSString alloc]initWithFormat: @"%i",x];
                    operatorLabel.text = [[NSString alloc]initWithFormat: @"÷"];
                    a = 5;
                }
                else a = 0;
                break;
                default:
                break;
        }
    }       
}
else
{
    UIAlertView *noOperatorSelectedAlert = [[UIAlertView alloc]initWithTitle:@"You have not set any operations."
                                                   message:@"Return to the settings menu and decide which operations you wish to perform. (addition, subtraction, etc.)"
                                                   delegate:self
                                                   cancelButtonTitle:@"Ok" 
                                                   otherButtonTitles:nil];
    [noOperatorSelectedAlert show];
    [noOperatorSelectedAlert release];
}
}
Run Code Online (Sandbox Code Playgroud)

Jim*_*vey 5

这里有一些事情要做.首先,您需要一种更好的方式来说明在用户做出任何明确决定之前的默认状态.接下来,您想知道何时应该从用户首选项刷新应用内状态.

默认初始化

第一项的解决方案是将默认值放入用户首选项的注册域中.这是您在应用程序初始化期间要做的事情,而不是让您的视图单独检查首选项并在初始化时更新它们.首选项系统在很多地方查找数据,它看起来的第一个位置是仅在内存中的注册域.这是您为每个用户首​​选项设置默认值(即没有指定值表示'x')的值.

您将使用的API是-[NSUserDefaults registerDefaults:],它采用NSDictionary一些值.要设置的默认值YES(在Objective-C的布尔类型使用YESNO,而不是TRUEFALSE)你会使用这样的事情,在共同执行+initialize的应用程序的主类方法:

+ (void) initialize
{
    // in any +initialize, make sure it's being called on your class
    // +initialize is different from all other methods in this respect
    if ( [self isKindOfClass: [MyApplicationDelegate class]] == NO )
        return;    // being called on a superclass, don't do my stuff

    // set up default values for certain preferences
    NSMutableDictionary * defaults = [NSMutableDictionary new];
    [defaults setObject: [NSNumber numberWithBool: YES] forKey: @"additionKey"];
    [defaults setObject: [NSNumber numberWithBool: YES] forKey: @"subtractionKey"];
    [defaults setObject: [NSNumber numberWithBool: YES] forKey: @"multiplicationKey"];
    [defaults setObject: [NSNumber numberWithBool: YES] forKey: @"divisionKey"];

    // set this as the registration domain
    [[NSUserDefaults standardUserDefaults] registerDefaults: defaults];
    [defaults release];
}
Run Code Online (Sandbox Code Playgroud)

通常你会把所有东西放到这样的一个方法中,所以如果你有其他部分的应用程序期望任何偏好的默认非零值,你应该将它们添加到这个组并将它放入你的应用程序委托的+initialize方法.

现在,当您的其他类使用[[NSUserDefault standardUserDefaults] boolForKey: @"additionKey"]并且没有任何内容保存到该键的首选项文件时,它们将获得上面提供的值.

刷新缓存值

因此,您可以看到用户可以更改这些首选项的视图.您的下一个工作是使上面的视图使用新的首选项更新其成员变量.为此,我们可以使用委托或通知.在这种情况下,我将通知原因:

  1. 您正在使用NSUserDefaults,理论上可以在许多不同的地方进行更改.委派只会告知您一个对象所做的更改.
  2. NSUserDefaults已经实现了一个方便的通知,您可以观看.

所以,在你的flashcardsViewController中,你将拥有类似这些方法的东西:

- (void) updateFromPreferences
{
    // fetch current values from user defaults into your member variables
    additionIsEnabled = [[NSUserDefaults standardUserDefaults] boolForKey: @"additionKey"];
    // etc...
}

- (void) viewWillLoad
{
    // load variables from user defaults
    [self updateFromPreferences];

    // find out when the preferences have been changed
    // this will cause -updateFromPreferences to be called
    // whenever something changes preferences, inside the app or outside
    [[NSNotificationCenter defaultNotificationCenter] addObserver: self
                                                         selector: @selector(updateFromPreferences)
                                                             name: NSUserDefaultsDidChangeNotification
                                                           object: nil];
}

- (void) viewDidUnload
{
    // always remove notification observers.
    [[NSNotificationCenter defaultNotificationCenter] removeObserver: self
                                                                name: NSUserDefaultsDidChangeNotification
                                                              object: nil];
}

- (void) dealloc
{
    // add this to your existing dealloc routine
    [[NSNotificationCenter defaultNotificationCenter] removeObserver: self
                                                                name: NSUserDefaultsDidChangeNotification
                                                              object: nil];
}
Run Code Online (Sandbox Code Playgroud)

摘要

总而言之,这两个应该为您提供完成这项工作所需的一切.