我有一个简单的测试应用程序来帮助我学习如何将数据从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。
我很绿,所以我希望这里的问题可能很明显。肯定会得到一些帮助。
答案 0 :(得分:1)
<强>问题:强>
[ViewController saveData];
您正在使用类名saveData
调用ViewController
方法。
但是saveData
是一个实例方法,而不是类方法。
-(void) saveData;
<强>修正:强>
1)将saveData
声明为类方法
+(void) saveData;
2)使用saveData
的对象调用ViewController
。
ViewController *vControl = [[ViewController alloc] init];
[vControl saveData];
答案 1 :(得分:0)
以前的答案(Midhun#2)可以使用,但我认为您最好使用应用程序输入背景通知并跳过代理。
只需将其添加到“view did load”:只要应用程序转到后台,它就会调用saveData。
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(saveData)name:UIApplicationDidEnterBackgroundNotification object:nil];
希望这有帮助。
答案 2 :(得分:0)
正如其他人所说,您的问题是[ViewController saveData]
方法调用明确暗示您正在尝试拨打“class method”,而您无疑需要调用“实例方法”(因为它是您的视图控制器的实例,其中包含您要保存的数据)。为此,您有两个基本选择:
您可以让您的应用委托调用视图控制器中的saveData
方法。
在各种评论中,你提到你“试图在每个方面以及在我能想象到的每个地方实例化VC。”别。 Midhun的例子是概念性的,说明了类和实例方法之间的区别。但是,当您想要调用实例方法时,您希望为视图控制器的现有实例调用此方法,而不是实例化新的视图控制器。
那么,您可能会问,如何获得对视图控制器的现有实例的引用?您要做的是(a)在您的app委托中创建一个属性,以使用saveData
方法保存对视图控制器的引用; (b)让视图控制器设置app委托的属性。因此,首先,在app delegate的.h文件中创建一个属性以引用视图控制器:
@property (weak, nonatomic) ViewController *viewController;
显然,不要忘记.h文件中的#import "ViewController.h"
行。
其次,让视图控制器的viewDidLoad
方法更新app delegate的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];
}
坦率地说,如果你采用这种技术,我可能会建议进一步改进,特别是采用委托协议模式,但是在你掌握了上述技术之后我会推迟这种对话。
比以上更简单的方法是完全取消此应用委托代理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
}
如您所见,我注册观察UIApplicationDidEnterBackgroundNotification
中的viewDidLoad
,同时确保在dealloc
中删除我的观察者。我还确保我的@selector
方法名称与我的方法名称完全匹配(例如,在我的示例中,没有参数,因此没有冒号)。