1

我有一个简单的测试应用程序来帮助我学习如何将数据从 NSMutableArray 持久化到 plist。一切似乎都运行良好,直到我尝试通过在 AppDelegate.m 文件中调用名为“saveData”的 ViewController 方法来保存数据:

- (void)applicationDidEnterBackground:(UIApplication *)application
{

    [ViewController saveData];
}

我得到一个“没有选择器‘saveData’的已知类方法,尽管该方法在 ViewController.h 中明确声明,如下所示:

//
//  ViewController.h
//  PlistTest
//
//  Created by Tim Jones on 10/30/13.
//  Copyright (c) 2013 TDJ. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController

@property (weak, nonatomic) IBOutlet UILabel *nameLabel;

@property (weak, nonatomic) IBOutlet UILabel *timeLabel;

@property NSMutableArray *mainActivityArray;



- (IBAction)buttonHit:(id)sender;

-(NSString *) getFilePath;
-(void) saveData;
-(void) loadData;


@end

并在 ViewController.m 中实现,因此:

//
//  ViewController.m
//  PlistTest
//
//  Created by Tim Jones on 10/30/13.
//  Copyright (c) 2013 TDJ. All rights reserved.
//

#import "ViewController.h"
#import "DataClass.h"

@interface ViewController ()

@end

@implementation ViewController

-(NSString *) getFilePath
{
    NSArray *pathArray = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    return [[pathArray objectAtIndex:0] stringByAppendingPathComponent:@"PlistTestData"];
}

-(void) saveData
{
    [self.mainActivityArray writeToFile: self.getFilePath atomically:YES];
}

我将 ViewController.h 导入 AppDelegate.h。

我很绿,所以我希望这个问题对这里的许多人来说可能很明显。肯定会感谢一些帮助。

4

3 回答 3

1

问题:

[ViewController saveData];

您正在saveData使用类名调用方法ViewController
但是saveData是实例方法,而不是类方法。

-(void) saveData;

修复:

1) 声明saveData为类方法

+(void) saveData;

2)saveData使用 的对象调用ViewController

ViewController *vControl = [[ViewController alloc] init];
[vControl saveData];
于 2013-11-01T19:14:07.780 回答
0

以前的答案(Midhun #2)可以工作,但我认为你最好使用 Application Did Enter Background Notification 并跳过委托。

只需将其添加到“view did load”:只要应用程序进入后台,它就会调用 saveData。

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(saveData) name:UIApplicationDidEnterBackgroundNotification object:nil];

希望这可以帮助。

于 2013-11-01T20:55:52.707 回答
0

正如其他人所指出的那样,您的问题是您的[ViewController saveData]方法调用清楚地表明您正在尝试调用“类方法”,并且您无疑想要调用您的“实例方法”(因为它是您的视图控制器实例)要保存的数据)。为此,您有两个基本选择:

  1. 您可以让您的应用程序委托调用saveData视图控制器中的方法。

    在各种评论中,您提到您“尝试在我能想象到的每个地方以各种方式实例化 VC”。不。Midhun 的示例是一个概念性的示例,说明了类和实例方法之间的区别。但是,当你想调用实例方法时,你想为你现有的视图控制器实例调用它,绝对不是实例化一个新的视图控制器。

    那么,你可能会问,如何获得对现有视图控制器实例的引用?您要做的是(a)在您的应用程序委托中创建一个属性,以使用该saveData方法保存对视图控制器的引用;(b) 让该视图控制器设置应用程序委托的该属性。因此,首先,在您的应用委托的 .h 文件中创建一个属性来引用视图控制器:

    @property (weak, nonatomic) ViewController *viewController;
    

    显然,不要忘记#import "ViewController.h".h 文件中的那一行。

    其次,让viewDidLoad视图控制器的方法更新应用程序委托的viewController属性:

    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
        AppDelegate *delegate = [[UIApplication sharedApplication] delegate];
        delegate.viewController = self;
    }
    

    同样,不要忘记#import "AppDelegate.h"在文件的顶部ViewController.m

    完成后,应用程序委托applicationDidEnterBackground现在可以引用您设置的这个属性viewDidLoad

    - (void)applicationDidEnterBackground:(UIApplication *)application
    {
        [self.viewController saveData];
    }
    

    坦率地说,如果你采用了这种技术,我可能会建议进一步改进,特别是采用委托协议模式,但我将把谈话推迟到你掌握了上述技术之后。

  2. 比上面更容易的是完全消除这个应用程序委托applicationDidEnterBackground代码,只让你的视图控制器本身响应与应用程序进入后台相关的系统通知。而且,不用说,您将这段代码直接放在视图控制器本身中。

    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(saveData) name:UIApplicationDidEnterBackgroundNotification object:nil];
    }
    
    - (void)dealloc
    {
        [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil];
    }
    
    - (void)saveData
    {
        // save your data here
    }
    

    如您所见,我注册观察UIApplicationDidEnterBackgroundNotificationin viewDidLoad,但也要确保删除我的观察者 in dealloc。我还确保我的@selector方法名称与我的方法名称完全匹配(例如,在我的示例中,没有参数,因此没有冒号)。

于 2013-11-02T06:51:06.963 回答