【问题标题】:iOS - NSUserDefaults Mutable Array not displaying when app is re-openediOS - 重新打开应用程序时不显示 NSUserDefaults 可变数组
【发布时间】:2014-04-17 17:44:01
【问题描述】:

这是我的mainAppDelegate.h

#import <UIKit/UIKit.h>

@interface mainAppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;
@property NSMutableArray *toDoItems;

@end

还有我的mainAppDelegate.m

#import "mainAppDelegate.h"

@implementation mainAppDelegate

- (void)applicationWillTerminate:(UIApplication *)application
{
    NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults];
    [defaults setObject:self.toDoItems forKey:@"toDoItems"];
    [defaults synchronize];
}
@end

我有另一个文件,XYZToDoListViewController.m,代码如下:

#import "XYZToDoListViewController.h"
#import "XYZToDoItem.h"
#import "XYZAddItemViewController.h"

@interface XYZToDoListViewController ()
@property NSMutableArray *toDoItems;
@end

@implementation XYZToDoListViewController

- (IBAction)unwindToList:(UIStoryboardSegue *)segue
{
    XYZAddItemViewController *source = [segue sourceViewController];
    XYZToDoItem *item = source.toDoItem;
    if (item != nil) {
        [self.toDoItems addObject:item];
        [self.tableView reloadData];
    }
}

- (IBAction)clearData:(UIBarButtonItem *)sender;
{
    [self.toDoItems removeAllObjects];
    [self.tableView reloadData];
}

- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {

}
return self;
}

   NSUserDefaults *defaults= [NSUserDefaults standardUserDefaults];
   if([[[defaults dictionaryRepresentation] allKeys] containsObject:@"toDoItems"]){
       NSLog(@"toDoItems found");
       self.toDoItems = [[NSMutableArray alloc]initWithArray:[[NSUserDefaults standardUserDefaults]objectForKey:@"toDoItems"]];
   } else {
      self.toDoItems = [[NSMutableArray alloc] init];
   }
   self.navigationController.view.backgroundColor =
   [UIColor colorWithPatternImage:[UIImage imageNamed:@"bg_full.png"]];
   self.tableView.backgroundColor = [UIColor clearColor];
   self.tableView.contentInset = UIEdgeInsetsMake(-35, 0, -35, 0);
   }
   @end

这至少是我认为相关的。我的基本框架是我从this tutorial. 遵循的

我做错了什么?当我将项目添加到我的待办事项列表中时,终止应用程序,然后重新启动应用程序,我之前输入的数据不会显示。项目没有错误或警告,也没有崩溃。

【问题讨论】:

  • 您没有显示添加@"mykey" NSUserDefaults 并调用save 的部分。
  • 你在哪里存储数组在NSUserDefaults
  • 请查看我的编辑。我不小心从早期版本中复制了我的代码。
  • 使用 -applicationWillResignActive 方法代替 -appliconWillTerminate

标签: ios objective-c nsmutablearray nsuserdefaults


【解决方案1】:

applicationWillTerminate: 不被称为我想,把用户默认的synchronize 代码放在其他地方。 顺便说一句,当你重新启动调试器时,进程只是被杀死,而不是“终止”。

这就是为什么我通常在每次数据更改时调用synchronize,以确保在崩溃时保存数据,或者只是在我重新启动调试器时保存数据。

【讨论】:

  • 你建议我把同步代码放在哪里?我尝试将applicationWillTerminate 移动到我也有的XYZToDoListViewController.m 页面,但无济于事。
  • 您应该在数据更改后立即进行同步。所以在你的视图控制器中是的。如果您的用户点击单元格或任何指示数据更改的交互 > synchronize
【解决方案2】:

在完全不同的旁注中,我想向您指出,您可以更改此设置

if([[[defaults dictionaryRepresentation] allKeys] containsObject:@"toDoItems"]){ NSLog(@"toDoItems found"); self.toDoItems = [[NSMutableArray alloc]initWithArray:[[NSUserDefaults standardUserDefaults]objectForKey:@"toDoItems"]]; } else { self.toDoItems = [[NSMutableArray alloc] init]; }

到此

self.toDoItems = [[NSMutableArray alloc]initWithArray:[[NSUserDefaults standardUserDefaults]objectForKey:@"toDoItems"]];

因为如果您尝试从用户默认值(或任何字典)中获取未设置的对象,您将得到 nil。如果你用一个 nil 数组初始化你的可变数组,你将有一个有效但为空的可变数组。

由于它不适合作为评论,因此我将其写为答案,尽管它当然与您的原始问题无关

【讨论】:

  • 实际上这最终成为了我问题的答案!我插入了更改并且它起作用了。谢谢!!
【解决方案3】:
[defaults setObject:self.toDoItems forKey:@"toDoItems"];


[[NSUserDefaults standardUserDefaults]objectForKey:@"loadItems"]

两者没有相同的密钥。您设置@"toDoItems" 并尝试获取@"loadItems"。

【讨论】:

  • 当然 - 仍然有问题,这是我的复制错误。
【解决方案4】:

您没有持久化数据。现在,当您创建一个项目时,它存在于内存中,但它永远不会写入磁盘,因此当应用程序终止时,包含该项目的内存将被释放。您需要将项目写入磁盘,以便在应用程序终止后可以使用它们。您可以归档项目,也可以使用 Core Data。不要使用 NSUserDefaults,它是用于用户设置的。Here 是存档的教程,您可以在 Apple 开发者网站上找到 Core Data 指南。

【讨论】:

  • 我之前有过这段代码:- (void)applicationWillTerminate:(UIApplication *)application { NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory = [paths objectAtIndex:0]; NSString *filePath = [documentsDirectory stringByAppendingPathComponent:@"toDoItems.plist"]; [self.toDoItems writeToFile:filePath atomically:TRUE]; } 并被告知我应该改用 UserDefaults。
  • 但我无法让该文件显示加载数据。
  • 不要使用 NSUserDefaults,这是为了用户偏好。如果我是你,我会创建一个名为 ToDoItem 的 NSObject 子类。确保它符合 NSCoder 协议,然后归档保存待办事项的数组。
  • 我让它与 UserDefaults 一起工作。我只使用简单的文本项,这是我目前需要做的事情。
【解决方案5】:

尝试模拟被调用的applicationWillTerminate 会非常困难。

我建议您在数据发生变化时(首选)或至少在更可预测的applicationWillEnterForeground:applicationWillResignActive: 上保存数据。

- (void) applicationWillResignActive:(UIApplication *)application
{
    NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults];
    [defaults setObject:self.toDoItems forKey:@"toDoItems"];
    [defaults synchronize];
}

正如 Emilie Lessard 指出的,您必须使用相同的密钥来获取正确的数据。

[[NSUserDefaults standardUserDefaults]objectForKey:@"toDoItems"];

【讨论】:

    【解决方案6】:

    我想您没有将列表保存在 mainAppDelegate 类中。因此,您需要将数据保存在正在形成列表的类上,并删除您的 mainAppDelegate 调用。当您的应用程序终止时,您可能正在保存一个 nil 值。

    NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults];
    [defaults setObject:self.toDoItems forKey:@"toDoItems"];
    [defaults synchronize];
    

    稍后您需要使用相同的键 @"toDoItems" 调用它。

    【讨论】:

    • 确保不要滥用 NSUserDefaults,它仅用于用户偏好,不适用于您想要持久的任何内容。
    猜你喜欢
    • 2017-09-29
    • 1970-01-01
    • 2012-07-03
    • 1970-01-01
    • 1970-01-01
    • 2014-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多