Save data even if the app re-opens - Swift Xcode 6 iOS - ios

I'm working on a app that can randomize love couples. Just a fun thing, okey!?!? :D
But the problem, or maybe not a problem but a thing that can be much better if I get this thing to be working. In the beginning you need to write in all the names. And thats takes some time... Should I use Core Date? I don't really knows what core data is so I'm not sure. I would love if a god come to me and wrote the full code that can remember an array even if the app and phone shuts down. I have done this in java, is that simpel that it is in java? That would be great!
//Thank, Anton

For Heavy, complex data structures you would want to use core data,
https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreData/Articles/cdTechnologyOverview.html#//apple_ref/doc/uid/TP40009296-SW1
But seeing as you just want to store an array, You should look into NSUserDefaults.
NSUserDefaults will store given data as long as the app is not deleted. You will most likely want to create some kind of custom DataStorage class for this.
#interface DataStorage : NSObject <NSCoding>
#property (nonatomic, strong) NSMutableArray *arrayToStore;
+ (instancetype)sharedInstance;
- (void)save;
#end
Above is the .h file. As you can see, it follows NSCoding protocols. That provides access to methods which allow you to encode data. You will use the save method to write the data to disk.
#import "DataStorage.h"
#implementation DataStorage
#synthesize arrayOfPeople = _arrayToStore;
+ (DataStorage *)sharedInstance
{
static DataStorage *state = nil;
if ( !state )
{
NSData *data =[[NSUserDefaults standardUserDefaults] objectForKey:#"DataStorageKey"];
if (data)
{
state = [NSKeyedUnarchiver unarchiveObjectWithData:data];
}
else
{
state = [[DataStorage alloc] init];
}
}
return state;
}
- (id)init{
if (self = [super init]) {
if (!_arrayToStore) {
_arrayToStore = [[NSMutableArray alloc] init];
}
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)decoder
{
self = [self init];
if (self) {
if ([decoder decodeObjectForKey:#"DataStorageArrayToStore"]) {
_arrayToStore = [[decoder decodeObjectForKey:#"DataStorageArrayToStore"] mutableCopy];
}
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:_arrayToStore forKey:#"DataStorageArrayToStore"];
}
- (void)save
{
NSData *appStateData = [NSKeyedArchiver archivedDataWithRootObject:self];
[[NSUserDefaults standardUserDefaults] setObject:appStateData forKey:#"DataStorageKey"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
#end
Here is the .m file, which pretty much evaluates to see if there is a saved instance of the class, and if not it will create one. [DataStorage sharedInstance]...
when you want to store some data, you will simply make the class available to said file, #import "DataStorage.m and then use
NSString *testData = [NSString stringWithFormat: #"Test Data String"];
[[DataStorage sharedInstance].arrayToStore addObject: testData];
[DataStorage sharedInstance] save];

Related

Objective-C Writing general getter and setter methods

In my project I have a settings class with properties with custom setters that access NSUserDefaults to make everything simpler. The idea is that Settings class has
#property NSString *name
which has custom getter that gets the name value from NSUserDefaults and a setter that saves the new value there. In this way throughout the whole project I interact with the Settings class only to manage user defined preferences. The thing is that it seems way too repetitive to write all the getters and setters (I have about 50 properties), and would like to create one setter and one getter that would work for all variables. My only issue is how to get hold of the name of the variable within the setter.
The final question then is: is it possible to find out within a getter or setter for which property is the function being called?
If you have some other approach I would appreciate it too but considering that I would like to keep all the NSUserDefaults stuff in one class, I can't think of an alternative that doesnt include writing 50 getters and setters.
Thanks!
Another approach could be this.
No properties, just key value subscript.
#interface DBObject : NSObject<NSCoding>
+ (instancetype)sharedObject;
#end
#interface NSObject(SubScription)
- (id)objectForKeyedSubscript:(id)key;
- (void)setObject:(id)obj forKeyedSubscript:(id <NSCopying>)key;
#end
On the implementation file:
+ (instancetype)sharedObject {
static DBObject *sharedObject = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedObject = [[DBObject alloc] init];
});
return sharedObject;
}
- (id)objectForKeyedSubscript:(id)key {
return [[NSUserDefaults standardUserDefaults] objectForKey:key];
}
- (void)setObject:(id)obj forKeyedSubscript:(id <NSCopying>)key {
[[NSUserDefaults standardUserDefaults] setObject:obj forKeyedSubscript:key];
[[NSUserDefaults standardUserDefaults] synchronize];
}
Now, you can use it like this:
// You saved it in NSUserDefaults
[DBObject sharedObject][#"name"] = #"John";
// You retrieve it from NSUserDefaults
NSLog(#"Name is: %#", [DBObject sharedObject][#"name"]);
I this this is the best approach and is what i will use in the future.
The setter and getter in this case is simple, you can do like this:
- (void)setName:(NSString *)name {
[[NSUserDefaults standardUserDefaults] setObject:name forKey:#"name"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
- (NSString *)name {
return [[NSUserDefaults standardUserDefaults] objectForKey:#"name"];
}
If you want to use a simple approach for all properties:
- (id)objectForKey:(NSString *)key {
return [[NSUserDefaults standardUserDefaults] objectForKey:key];
}
- (void)setObject:(id)object forKey:(NSString *)key {
[[NSUserDefaults standardUserDefaults] setObject:object forKey:key];
[[NSUserDefaults standardUserDefaults] synchronize];
}
Instead of creating many properties, create many keys, each key is something you want to save or retrieve.
Example of keys:
static NSString *const kName = #"name";
static NSString *const kLastName = #"lastName";
I found your question very interesting and I said to myself "Challenge accepted!".
I've created this project on Github.
Basically, all you have to do is subclass the VBSettings class and then declare de properties, like this:
#interface MySettings : VBSettings
#property (strong, nonatomic) NSString *hello;
#end
The value of "hello" will be saved to NSUserDefaults with the key "hello". Example of usage:
MySettings settings = [[MySettings alloc] init];
settings.hello = "World!"; //The value is saved in NSUserDefaults
NSLog(#"%#", settings.hello); //The value is restored from NSUserDefaults.
One possibility would be to use KVO to detect when your properties change.
E.g.:
#interface Settings : NSObject
#property NSString *one;
#property NSString *two;
#end
#implementation Settings
- (instancetype)init
{
self = [super init];
if (self) {
[self addObserver:self forKeyPath:#"one" options:NSKeyValueObservingOptionNew context:NULL];
[self addObserver:self forKeyPath:#"two" options:NSKeyValueObservingOptionNew context:NULL];
}
return self;
}
- (void)dealloc
{
[self removeObserver:self forKeyPath:#"one"];
[self removeObserver:self forKeyPath:#"two"];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
NSLog(#"Key: %#, Change: %#", keyPath, change);
}
#end
In a different class, use the standard property access:
Settings *settings = [[Settings alloc] init];
settings.one = #"something for one";
The Settings object logs:
Key: one, Change: {
kind = 1;
new = "something for one"; }
You could try to use dynamic Getter and Setter declarations as noted in this answer.
First create generic functions that you want all the properties to use:
- (id)_getter_
{
return [[NSUserDefaults standardUserDefaults] objectForKey:NSStringFromSelector(_cmd)];
}
- (void)_setter_:(id)value
{
//This one's _cmd name has "set" in it and an upper case first character
//This could take a little work to parse out the parameter name
[[NSUserDefaults standardUserDefaults] setObject:object forKey:YourParsedOutKey];
[[NSUserDefaults standardUserDefaults] synchronize];
}
Then create the dynamic method generator:
+(void)synthesizeForwarder:(NSString*)getterName
{
NSString*setterName=[NSString stringWithFormat:#"set%#%#:",
[[getterName substringToIndex:1] uppercaseString],[getterName substringFromIndex:1]];
Method getter=class_getInstanceMethod(self, #selector(_getter_));
class_addMethod(self, NSSelectorFromString(getterName),
method_getImplementation(getter), method_getTypeEncoding(getter));
Method setter=class_getInstanceMethod(self, #selector(_setter_:));
class_addMethod(self, NSSelectorFromString(setterName),
method_getImplementation(setter), method_getTypeEncoding(setter));
}
Then set what strings you want to create dynamic getters and setters for:
+(void)load
{
for(NSString*selectorName in [NSArray arrayWithObjects:#"name", #"anything", #"else", #"you", #"want",nil]){
[self synthesizeForwarder:selectorName];
}
}
That will create getters and setters for any variable name that you add to the array. I'm not sure how well this will work when other classes try to call these methods, the compiler won't see them at compile time so may throw errors when you try to use them. I just combined 2 other
StackOverflow questions into this one answer for your situation.
Dynamic Getters and Setters.
Get current Method name.
As I understand it, you don't want the mental overhead of setObject:forKey: and objectForKey: method calls by the user of this class.
Here is how to get round it. I am leaving a lot of gaps for you to fill in.
Declare the property in the header file, so that callers can use it:
#property NSString *something;
#property NSString *somethingElse;
In the class file itself, declare that you are defining the properties, so that the compiler doesn't get upset:
#dynamic something,somethingElse;
In the class file, implement the methodSignatureForSelector function, like this:
-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{if (SelectorIsGetter(aSelector))
return [NSMethodSignature signatureWithObjCTypes:"##:"];
if (SelectorIsSetter(aSelector))
return [NSMethodSignature signatureWithObjCTypes:"v#:#"];
return nil;
}
This will tell the system to call forwardInvocation: for these selectors, and will also tell it the shape of the call that is being made.
Your implementation of SelectorIsGetter and SelectorIsSetter is up to you. You will probably use NSStringFromSelector(aSelector) to get the selector's name, and then look it up in a table of names to see if it matches any of the names of the selectors you are implementing: in this case something and somethingElse for the getters and setSomething: and setSomethingElse: for the setters.
In the class file, implement the forwardInvocation: function, like this:
-(void)forwardInvocation:(NSInvocation *)anInvocation
{if (SelectorIsGetter(anInvocation.selector))
{NSString *s=[self objectForKey:NSStringFromSelector(anInvocation.selector)];
[anInvocation setReturnValue:&s];
return;
};
if (SelectorIsSetter(anInvocation.selector))
{NSString *s;
[anInvocation getArgument:&s atIndex:2];
[self setObjectForKey:UnmangleName(NSStringFromSelector(anInvocation.selector))];
return;
};
[super forwardInvocation:anInvocation];
}
…where UnmangleName is a thoroughly tedious function that takes a string like "setSomething:" and turns it into a string like "something".
If you want to do more than just NSStrings, the extension is reasonably straightforward.

How to archive and unarchive an NSObject?

I am trying to archive an NSObject that I send through match data in a game center turn based game.
Below is my code for archiving my object
turnDataObject MyData = [[turnDataObject alloc] init];
data = [NSKeyedArchiver archivedDataWithRootObject:MyData];
This is my code for unarchiving my object
readMyData = [NSKeyedUnarchiver unarchiveObjectWithData:data] ;
However when I run this code I get an error
thread 1 exc bad access code
I think that this might have to do with sending addresses when I archive data. How do I send something that will be readable when I unarchive it?
Edit 1: I get the error on the next line after I unarchive. it says that the adress I am trying to access is null. I remember reading somewhere that I souldn't send adresses of my NSObject but I am not sure how to convert it to something else.
readMyData = [NSKeyedUnarchiver unarchiveObjectWithData:data] ;
NSLog(#"current game happens to be: %#", readMyData.currentGame);
Edit 2: here is my init with coder and encode with coder
- (instancetype)initWithCoder:(NSCoder *)decoder
{
self = [self init];
if (self) {
_currentGame = [decoder decodeObjectForKey:currentGameDataKey];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder
{
//scores data keys
[encoder encodeObject:self.currentGame forKey:currentGameDataKey];
}
Edit 3: _currentGame is in my objects .h file
#property (assign, nonatomic) NSString *currentGame;
I would suggest creating NSKeyedArchiver and NSKeyedUnarchiver objects and using those instead of using the type (which it looks like you're doing.)
I usually program in Swift but here's a shot at example code:
theArchiver NSKeyedArchiver = [[theArchiver alloc] init];
data = [theArchiver archivedDataWithRootObject:MyData];
Then you would do the same thing with the NSKeyedUnarchiver.
Your initWithCoder implementation is wrong:
self = [self init];
That should be:
self = [super init];
You need to add NSCoding protocol to MyData Class, here is the code snippet with supporting NSCoding in order to add Archiving support to NSObjet.
MyData.h
#interface MyData : NSObject <NSCoding>
#property (nonatomic, strong) NSString *currentGame;
#end
MyData.m
//This method is optional, if you need constructor for current game
- (instancetype)initWithCurrentGame:(NSDictionary *)currentGame {
self = [super init];
if (self) {
self.currentGame = currentGame;
}
return self;
}
-(void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:self.currentGame forKey:#"currentGame"];
}
-(id)initWithCoder:(NSCoder *)decoder {
self.currentGame = [decoder decodeObjectForKey:#"currentGame"];
return self;
}

Encoding, decoding, and editing a NSMutableArray with NSCoding

I followed along with Ray Wenderlich's tutorial for saving game data using a singleton and NSCoding (http://www.raywenderlich.com/63235/how-to-save-your-game-data-tutorial-part-1-of-2). Everything they did I've been able to use for NSStrings (changing value, storing, using in my project). I tried to make an NSMutableArray so I could add to and save a list of strings, though, and it didn't work. There is probably a very simple solution to this, so thanks in advance for putting up with a newbie.
My code:
in RWGameData.h (my singleton for using game data):
#property (nonatomic, strong) NSMutableArray *dataArray;
in RWGameData.m, after #implementation:
static NSString* const GameDataArrayofValues = #"dataArray";
-(void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:self.dataArray forKey:GameDataArrayofValues];
}
-(instancetype)initWithCoder:(NSCoder *)decoder {
self = [self init];
if (self) {
_dataArray = [[decoder decodeObjectForKey:GameDataArrayofValues] mutableCopy];
}
return self;
}
(there's also all the other code from that tutorial, like a save method etc.)
in myGame.m
[[RWGameData sharedGameData].dataArray addObject:#"objectString"];
[[RWGameData sharedGameData] save];
Logging the contents of the array right after this shows it as empty. [RWGameData sharedGameData].dataArray accepts the addObject call because I created it as an NSMutableArray, but it seems like it isn't actually going through.
Any ideas?
My guess is _dataArray is nil.
You should add code to your initWithCoder that checks to see if it was able to read array data. If not, _dataArray will be nil. In that case you should initialize an empty mutable array.
Your updated initWithCoder might look like this:
-(instancetype)initWithCoder:(NSCoder *)decoder {
self = [self init];
if (self)
{
_dataArray = [[decoder decodeObjectForKey:GameDataArrayofValues] mutableCopy];
if (_dataArray)
_dataArray = [[NSMutableArray alloc] init];
}
return self;
}
Likewise you need to implement a "regular" init method that sets _dataArray to an empty mutable array.

NSCoding and saving/loading default values issue

I'm writing some code for an iPhone app, and I'm having issues getting default data to load in correctly. I am basing my code off some example from the "Learning Cocos2d" book by Ray Wenderlich.
It seems that even when I delete the app outright and try to start from fresh data that the app inconsistently either doesn't try to load the data, or incorrectly thinks that there is data, and loads null.
I'm using containsValueForKey to check if a value exists and then load it or load some default value, but even on a fresh installation the containsValueForKey finds data and doesn't load the defaults. In xcode's organizer I checked my device's file structure and the Documents folder, where I specified to save, doesn't look like it contains any files, so I'm not sure what it's grabbing.
My guess is that the problem is something to do with the initWithCoder function. It seems to mysteriously go through the function sometimes, but not all the time. Another weird thing is that I call [[GameManager sharedGameManager] save] when the player gets a highscore (not shown here, but the code is the exact same as this objectiveList, only an int) and it appears to save it correctly.
And now the code:
GCDatabase.h
#import <Foundation/Foundation.h>
id loadData(NSString * filename);
void saveData(id theData, NSString *filename);
GCDatabase.m
#import "GCDatabase.h"
NSString * pathForFile(NSString *filename) {
// 1
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
// 2
NSString *documentsDirectory = [paths objectAtIndex:0];
// 3
return [documentsDirectory stringByAppendingPathComponent:filename];
}
id loadData(NSString * filename) {
NSString *filePath = pathForFile(filename);
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
NSData *data = [[[NSData alloc] initWithContentsOfFile:filePath] autorelease];
NSKeyedUnarchiver *unarchiver = [[[NSKeyedUnarchiver alloc] initForReadingWithData:data] autorelease];
id retval = [unarchiver decodeObjectForKey:#"Data"];
[unarchiver finishDecoding];
return retval;
}
return nil;
}
void saveData(id theData, NSString *filename) {
NSMutableData *data = [[[NSMutableData alloc] init] autorelease];
NSKeyedArchiver *archiver = [[[NSKeyedArchiver alloc] initForWritingWithMutableData:data] autorelease];
[archiver encodeObject:theData forKey:#"Data"];
[archiver finishEncoding];
[data writeToFile:pathForFile(filename) atomically:YES];
}
GameManager.h
#interface GameManager : NSObject <NSCoding>{
NSMutableArray *objectiveDescriptions;
}
#property (nonatomic, retain) NSMutableArray * objectiveDescriptions;
+(GameManager*)sharedGameManager;
-(void)save;
-(void)load;
-(void)encodeWithCoder:(NSCoder *)encoder;
-(id)initWithCoder:(NSCoder *)decoder;
#end
GameManager.m (I added the load function, in an attempt to force it to load, but it doesn't seem to work)
+(GameManager*)sharedGameManager {
#synchronized([GameManager class])
{
if(!sharedGameManager) {
sharedGameManager = [loadData(#"GameManager") retain];
if (!sharedGameManager) {
[[self alloc] init];
}
}
return sharedGameManager;
}
return nil;
}
+(id)alloc {
#synchronized([GameManager class]){
NSAssert(sharedGameManager == nil, #"Attempted to allocate a second instance of the Game Manager singleton");
sharedGameManager = [super alloc];
return sharedGameManager;
}
return nil;
}
- (void)dealloc {
[objectiveList release];
[super dealloc];
}
- (void)save {
saveData(self, #"GameManager");
}
-(void)load {
loadData(#"GameManager");
}
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:objectiveList forKey:#"objectiveList"];
}
- (id)initWithCoder:(NSCoder *)decoder {
self = [super init];
if (self != nil) {
if ([decoder containsValueForKey:#"objectiveList"]) {
objectiveList = [decoder decodeObjectForKey:#"objectiveList"];
} else {
[objectiveList addObjectsFromArray:[NSArray arrayWithObjects:#"1",#"2",#"3",#"4",#"5", nil]];
}
}
return self;
}
#end
I have not read your full code.. But I found a problem in code....
You have not allocated memory to objectiveList array.. Unless and until you allocate memory to array, objects will not be added...
I think go for
objectiveList = [[NSMutableArray alloc] initWithArray:[NSArray arrayWithObjects:#"1",#"2",#"3",#"4",#"5", nil]];
instead of
[objectiveList addObjectsFromArray:[NSArray arrayWithObjects:#"1",#"2",#"3",#"4",#"5", nil]];
Check for the syntax.. Hope this may help as it troubled me also in the past where I forgot to allocate memory to the array.. And kept on adding objects resulting in null... :)
In case it doesn't solve your problem, I'll look for code later completely.. :)
I seem to see the problem. When the constructor is called the first time, the objectiveList is not even created as the "initWithCoder" is never called. You have to override the init method as well in order for the objectiveList array to be constructed. Basically, the code that is calling the init method is in here:
+(GameManager*)sharedGameManager {
#synchronized([GameManager class])
{
if(!sharedGameManager) {
sharedGameManager = [loadData(#"GameManager") retain];
if (!sharedGameManager) {
[[self alloc] init]; // GOES INTO INIT METHOD, NOT INITWITHCODER!
}
}
return sharedGameManager;
}
return nil;
}
On a side note, that singleton implementation gave me a headache. Just saying. :)
There is (as far as I can see from the code you have provided) a logic flaw in your code. Consider what would happen if decoder did not contain an objectiveList key; the else clause would execute, but you never allocated objectiveList so the addObjectsFromArray: call will silently fail.
To test this theory, alter your code as show below, and rerun. If the assertion fires then the above theory is correct, if not you need to hunt a bit more!
- (id)initWithCoder:(NSCoder *)decoder
{
self = [super init];
if (self != nil)
{
if ([decoder containsValueForKey:#"objectiveList"])
{
objectiveList = [decoder decodeObjectForKey:#"objectiveList"];
}
else
{
NSAssert(objectiveList, #"objectiveList must be non-nil to add objects.");
[objectiveList addObjectsFromArray[NSArrayarrayWithObjects:#"1",#"2",#"3",#"4",#"5", nil]];
}
}
return self;
}
By the way, objectiveList is never declared as an ivar... I am sort of assuming that objectiveList and objectiveDescriptions are meant to be the same.
The method in GameManager.m should look like this:
- (id)initWithCoder:(NSCoder *)decoder {
self = [super init];
if (self != nil) {
if ([decoder containsValueForKey:#"objectiveList"]) {
objectiveList = [[decoder decodeObjectForKey:#"objectiveList"] retain];
} else {
objectiveList = [[NSMutableArray alloc] initWithObjects:#"1",#"2",#"3",#"4",#"5", nil];
}
}
You have two cases: either objectiveList is present, in which case you have previously saved some data, or it is not present and you need to create the default data (1, 2, 3, 4, 5). In the code above, I have changed the first case to retain the array returned by decodeObjectForKey, since Apple's docs state that this method returns an autorelease object. You need to retain it here to prevent the memory from being reused for some other objects that are created later in your app. By not retaining objectiveList, when accessing it later you were probably accessing garbage results (i.e. random memory) rather than what you had just decoded.
On a similar note, in the second case where objectiveList was not already present - i.e. for a new install of the app where there is no saved data present - you are not allocating objectiveList before trying to add objects to it. I have changed this line to actually alloc the object (and therefore the memory required), and then init with the default values you want. Since you were previously trying to add items to an array that had not been created, you would again get garbage data when trying to access the values from it. Note that I assume you are using an NSMutableArray here, but you might also be using an NSMutableSet.

How to save a (custom) NSObject in Core Data

In my application i have an custom NSObject, which contains 2 mutable Arrays.
I need to save this custom NSOBject into a core data entity, but i have no real idea how i can accomplish that...
After some searching, i found out, that the best way would be to convert the nsobject to nsdata and save it in an transformable field of the entity... but i m not sure how to do that.
can someone help me?
heres to code for my custom object:
MeasureData.h
#interface MeasureData : NSObject{
}
#property (nonatomic, strong) NSMutableArray *questionsData;
#property (nonatomic, strong) NSMutableArray *answersData;
- (id) init;
#end
MeasureData.m
#import "MeasureData.h"
#implementation MeasureData
#synthesize questionsData;
#synthesize answersData;
#pragma mark -
#pragma mark int
- (id)init
{
self = [super init];
// Initalize questions array (width data from plist)
questionsData = self.makeQuestionsArray;
// NSLog(#"loaded questions array: %#",questionsData); // debug
// Initalize answers array
answersData = self.makeAnswersArray;
// NSLog(#"loaded answers array: %#",answersData); // debug
return self;
}
-(NSMutableArray *)makeQuestionsArray
{
// Initalize questions array (width data from plist)
NSString *path = [[NSBundle mainBundle] pathForResource:
#"questions.list" ofType:#"plist"];
NSMutableArray *questions = [NSMutableArray arrayWithContentsOfFile:path];
/*
[questionsData insertObject:(NSString *)string atIndex:0];
*/
return questions;
}
-(NSMutableArray *)makeAnswersArray
{
// Initalize answers array
NSMutableArray *answers = [NSMutableArray arrayWithCapacity:0];
return answers;
}
-(id)initWithCoder:(NSCoder *)decoder {
if ((self=[super init])) {
questionsData = [decoder decodeObjectForKey:#"questionsData"];
answersData = [decoder decodeObjectForKey:#"answersData"];
}
return self;
}
-(void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:questionsData forKey:#"questionsData"];
[encoder encodeObject:questionsData forKey:#"questionsData"];
}
#end
According to the first comment, i implemented the encoder/coder functions for my custom class. And tried to archive and encode it (i m new to ios, so it could be completly wrong) - but it dont work... can someone tell me whats wrong?
heres the encoding (which dont work XD):
NSMutableData *dataToSave = (NSMutableData *)self.measureData;
NSKeyedArchiver *archiverForData = [[NSKeyedArchiver alloc] initForWritingWithMutableData:dataToSave];
[archiverForData encodeObject:dataToSave forKey:#"dataToSave"];
[archiverForData finishEncoding];
//
//theMeasure is the CoreData Entity
theMeasure.result = dataToSave;
In outline:
create a NSMutableData
create a NSKeyedArchiver with initForWritingWithMutableData over your data
serialize your arrays / objects / whatever you need (that implements NSCoding) with encode... methods of NSCoder
create a managed object with a BLOB (binary data) type field
write your encoded data from the mutable data to this field of the managed object.
In my answer to this question you can find some useful links: NSCoding VS Core data

Resources