Share custom data with today extension by NSUserDefaults - ios

this is my first post, so please be kind and constructive with me.
Im trying to share an array of custom objects with my Today Extension via NSuserDefauls.
I know that I can't put custom objects in NSUserdefaults so i coded them by NSKeyedArchiver - NSKeyedUnarchiver to transform them in NSData.
This is my custom class
#import "Counter.h"
#implementation Counter
#dynamic city;
#dynamic address;
#dynamic event;
#dynamic date;
#dynamic time;
#dynamic counter;
#dynamic latitude;
#dynamic longitude;
- (void)encodeWithCoder:(NSCoder *)encoder
{
//Encode properties, other class variables, etc
[encoder encodeObject:self.city forKey:#"city"];
[encoder encodeObject:self.address forKey:#"address"];
[encoder encodeObject:self.event forKey:#"event"];
[encoder encodeObject:self.date forKey:#"date"];
[encoder encodeObject:self.time forKey:#"time"];
[encoder encodeObject:self.counter forKey:#"counter"];
[encoder encodeObject:self.latitude forKey:#"latitude"];
[encoder encodeObject:self.longitude forKey:#"longitude"];
}
- (id)initWithCoder:(NSCoder *)decoder
{
self = [super init];
if( self != nil )
{
self.city = [decoder decodeObjectForKey:#"city"];
self.address = [decoder decodeObjectForKey:#"address"];
self.event = [decoder decodeObjectForKey:#"event"];
self.date = [decoder decodeObjectForKey:#"date"];
self.time = [decoder decodeObjectForKey:#"time"];
self.counter = [decoder decodeObjectForKey:#"counter"];
self.latitude = [decoder decodeObjectForKey:#"latitude"];
self.longitude = [decoder decodeObjectForKey:#"longitude"] ;
}
return self;
}
#end
This is the coding function inside the app.
- (void)saveInUserDefault {
//Counter is my Custom class
//I'm Using MagicalRecord
NSArray *array = [Counter MR_findAllSortedBy:#"date" ascending:NO];
NSMutableArray *defaultMutableArray = [NSMutableArray arrayWithCapacity:array.count];
NSUserDefaults *defaultArray = [[NSUserDefaults alloc] initWithSuiteName:#"group.LorenzoLoRe.Everycount"];
for (Counter *cnt in array) {
NSData *dataToDefault = [NSKeyedArchiver archivedDataWithRootObject:cnt];
[defaultMutableArray addObject:dataToDefault];
}
[defaultArray setObject:defaultMutableArray forKey:#"counts"];
[defaultArray synchronize];
}
At this point looking at the log, data seems to be write in NSUserDefaults
And here i try to retrive the data in the Extension
-
(void)takeLastCounts {
NSUserDefaults *defaultArray = [[NSUserDefaults alloc] initWithSuiteName:#"group.company.product"];
[defaultArray synchronize];
NSArray *dummyArray = [defaultArray arrayForKey:#"counts"];;
NSMutableArray *arrayFromDefault= NULL;
Counter *cter = nil;
for (NSData *data in dummyArray) {
cter = [NSKeyedUnarchiver unarchiveObjectWithData:data];
[arrayFromDefault addObject:cter];
}
self.cnt_1 = arrayFromDefault[0];
self.cnt_2 = arrayFromDefault[1];
NSDateFormatter * formatter = [[NSDateFormatter alloc] init];
[formatter setDateStyle:NSDateFormatterShortStyle];
self.eventLabel.text = self.cnt_1.event;
self.dateLabel.text = [formatter stringFromDate:self.cnt_1.date];
self.counterLabel.text = self.cnt_1.counter.stringValue;
self.timeLabel.text = self.cnt_1.time;
}
When i try to execute the Extension, theres no errors but just empty Arrays.
In particular NSArray *dummyArray = [defaultArray arrayForKey:#"counts"]; seems to be empty, so somewhere the data don't flows.
What I'm doing wrong??
Any kind of tips will be ver appreciate.

Related

How could I encode an Objective C object instance as a string?

I know there are various ways of archiving objects in objective-c, but is there some way which I can use to turn an object in Objective-C into a string which I can store in a txt file (amongst other data) and then extract from the file to recreate the same object instance again efficiently?
Thanks in advance
It's not recommended to do this.
Why don't you save the object into NSDefaults and extract if from there whenever you want? It's very simple and efficient.
Here is an example.
Let's say you have a User object defined as below
User.h
#interface User : NSObject
#property (nonatomic, strong) NSNumber *id;
#property (nonatomic, strong) NSString *first_name;
#property (nonatomic, strong) NSString *last_name;
#end
User.m
#import "User.h"
#implementation User
-(void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:id forKey:#"id"];
[encoder encodeObject:first_name forKey:#"first_name"];
[encoder encodeObject:last_name forKey:#"last_name"];
}
-(id)initWithCoder:(NSCoder *)decoder {
if (self = [super init]) {
self.id = [decoder decodeObjectForKey:#"id"];
self.first_name = [decoder decodeObjectForKey:#"first_name"];
self.last_name = [decoder decodeObjectForKey:#"last_name"];
}
}
- (id)initWith:(User *)obj {
if (self = [super init]) {
self.id = obj.id;
self.first_name = obj.first_name;
self.last_name = obj.last_name;
}
}
#end
Whenever you want to save the object, you can do something like that
//Save the user object
User *user = [[User alloc] init];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:user];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:data forKey:#"YOUR_KEY"];
[defaults synchronize];
//Get the user object
NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:#"YOUR_KEY"];
User *user = [[User alloc] initWith:[NSKeyedUnarchiver unarchiveObjectWithData:data]];

store NSobject data into Nsuserdefaults

In My Modal Object two values are there
I'm trying to store in NSUserDefaults. This is My Code
interface File:
#interface collectionModel : NSObject <NSCoding> {
}
#property(nonatomic,retain) NSString *name;
#property(nonatomic,retain) NSString *author;
Implementation File:
#implementation collectionModel
#synthesize name = _name;
#synthesize author = _author;
- (id)initWithCoder:(NSCoder *)aDecoder {
if (self = [super init]) {
self.name = [aDecoder decodeObjectForKey:#"name"];
self.author = [aDecoder decodeObjectForKey:#"author"];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:_name forKey:#"name"];
[aCoder encodeObject:_author forKey:#"author"];
}
ViewController.M
#import "collectionModel.h"
parsedCollectionArr = [[NSMutableArray alloc] init];
for (NSDictionary *obj in collectionBalk) {
NSString * Name = [obj objectForKey:#"Name"];
NSString * author = [obj objectForKey:#"author"];
collectionModel *dataObj = [[collectionModel alloc] init];
dataObj.name = Name;
dataObj.author = author;
[parsedCollectionArr addObject:dataObj];
}
NSLog(#"parsedCollectionArr count ---->>>> %d",23);
Here I want to store this parsedCollectionArr in NSUserDefaults and retrive from it.can any one help me.
try this..
Create a class like "CollectionModelManager.h and .m"
//For Save CollectionModel
+ (void)saveCollectionModel:(CollectionModel *) collectionModel
{
NSData *encodedData = [NSKeyedArchiver archivedDataWithRootObject:collectionModel];
NSUserDefaults *userDef = [NSUserDefaults standardUserDefaults];
[userDef setObject:encodedData forKey:kCollectionModelKey]; //here kCollectionModelKey is a static string
[userDef synchronize];
}
//For Get CollectionModel
+ (CollectionModel *)getCollectionModel
{
NSUserDefaults *userDef = [NSUserDefaults standardUserDefaults];
CollectionModel *collectionModel = nil;
NSData *encodedData = [userDef objectForKey:kCollectionModelKey]; //Same static string use here kCollectionModelKey
if (encodedData != nil) {
collectionModel = [NSKeyedUnarchiver unarchiveObjectWithData:encodedData];
}
return collectionModel;
}

Add Data to a Singleton instance array

I have a class "DataStorage", in which i wish to use NSCoding protocols to save data. However, when try to add to an array of that class,
[DataStorage sharedData].firstNameArray addObject:firstName:];
When viewing the breakpoint in the DataStorage class it shows the array to be of "nil" value
Here's the class implementation...
#import "DataStorage.h"
#implementation DataStorage
#synthesize firstNameArray = _firstNameArray;
#synthesize surnameArray = _surnameArray;
#synthesize companyArray = _companyArray;
#synthesize positionArray = _positionArray;
#synthesize emailArray = _emailArray;
#synthesize mobileArray = _mobileArray;
#synthesize productArray = _productArray;
+ (instancetype)sharedData {
static id sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [self loadInstance];
});
return sharedInstance;
}
- (instancetype)initWithCoder:(NSCoder *)decoder
{
self = [self init];
if (self) {
_firstNameArray = [decoder decodeObjectForKey:#"DataStorageFirstNameKey"];
_surnameArray = [decoder decodeObjectForKey:#"DataStorageSurnameKey"];
_companyArray = [decoder decodeObjectForKey:#"DataStorageCompanyKey"];
_positionArray = [decoder decodeObjectForKey:#"DataStoragePositionKey"];
_emailArray = [decoder decodeObjectForKey:#"DataStorageEmailKey"];
_mobileArray = [decoder decodeObjectForKey:#"DataStorageMobileKey"];
_productArray = [decoder decodeObjectForKey:#"DataStorageProductKey"];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:_firstNameArray forKey:#"DataStorageFirstNameKey"];
[encoder encodeObject:_surnameArray forKey:#"DataStorageSurnameKey"];
[encoder encodeObject:_companyArray forKey:#"DataStorageCompanyKey"];
[encoder encodeObject:_positionArray forKey:#"DataStoragePositionKey"];
[encoder encodeObject:_emailArray forKey:#"DataStorageEmailKey"];
[encoder encodeObject:_mobileArray forKey:#"DataStorageMobileKey"];
[encoder encodeObject:_productArray forKey:#"DataStorageProductKey"];
}
+ (NSString*)filePath
{
static NSString* filePath = nil;
if (!filePath) {
filePath =
[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]
stringByAppendingPathComponent:#"datastorage"];
}
return filePath;
}
+ (instancetype)loadInstance
{
NSData* decodedData = [NSData dataWithContentsOfFile: [DataStorage filePath]];
if (decodedData) {
DataStorage * dataStorage = [NSKeyedUnarchiver unarchiveObjectWithData:decodedData];
return dataStorage;
}
return [[DataStorage alloc] init];
}
- (void)save
{
NSData* encodedData = [NSKeyedArchiver archivedDataWithRootObject: self];
[encodedData writeToFile:[DataStorage filePath] atomically:YES];
}
#end
First of all, the _firstNameArray should be a mutable array but the array you get from [decoder decodeObjectForKey:#"DataStorageFirstNameKey"]; is not mutable, so you must create one.
Second, when you first use the instance, there is not file, so you will get nil in _fileNameArray, at this time, you should create a empty mutable array instead so you can add item in it.
- (instancetype)initWithCoder:(NSCoder *)decoder
{
self = [self init];
if (self) {
_firstNameArray = [[decoder decodeObjectForKey:#"DataStorageFirstNameKey"] mutableCopy];
if (!_firstNameArray) {
_firstNameArray = [NSMutableArray array] ;
}
}
return self;
}
So are the other properties.

Saving a NSMutableArray of custom objects

I am trying to save an NSMutableArray to the NSUserDeafults. I have implemented the NSCoding protocol methods as so
-(id)initWithCoder:(NSCoder*)aDecoder{
self = [super init];
if(self!= nil){
self.subject = [aDecoder decodeObjectForKey:#"subj"];
self.notes = [aDecoder decodeObjectForKey:#"notes"];
self.dateDue = [aDecoder decodeObjectForKey:#"date"];
self.done = [[aDecoder decodeObjectForKey:#"done"] boolValue];
self.importancy = [aDecoder decodeObjectForKey:#"imp"];
}
return self;
}
and
-(void)encodeWithCoder:(NSCoder*)enCoder{
[enCoder encodeObject:self.subject forKey:#"subj"];
[enCoder encodeObject:self.notes forKey:#"notes"];
[enCoder encodeObject:self.dateDue forKey:#"date"];
[enCoder encodeObject:self.importancy forKey:#"imp"];
[enCoder encodeObject:[NSNumber numberWithBool:self.done] forKey:#"done"];
}
i save it like this
[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:hwArray] forKey:ARRAY_KEY];
and get it like this
NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults];
NSData *hwData = [currentDefaults objectForKey:ARRAY_KEY];
if (hwData != nil)
{
NSLog(#"data is not nil");
NSArray *savedHWArray = [NSKeyedUnarchiver unarchiveObjectWithData:hwData];
if (savedHWArray != nil){
NSLog(#"initiating array");
hwArray = [[NSMutableArray alloc] initWithArray:savedHWArray];
NSLog(#"hw array count: %i",[hwArray count]);
}
else{
hwArray = [[NSMutableArray alloc] init];
}
}
It seems perfect according to this question, yet I can't seem to load it beacuse even though I've put objects into the array and loaded it the array is always nil at another run. Any idea on what's the problem?
Another option would be to write your objects out to a file instead of NSUserDefaults. Check out the answer to this question here for a full code example of how to do that.

Unable to decode object from NSUserDefaults

I'm trying to decode my object from NSUserdefaults.
If I debug the function initWithCoder, it's executed okay, but when I look at my object that was decoded, all the properties are nil.
My initWithCoder function:
-(id)initWithCoder:(NSCoder *)decoder
{
self = [super init];
if ( self != nil )
{
//decode the properties
self.SGTIN = [decoder decodeObjectForKey:#"SGTIN"];
self.GTIN = [decoder decodeObjectForKey:#"GTIN"];
self.SerialNumber = [decoder decodeObjectForKey:#"SerialNumber"];
self.Product = [decoder decodeObjectForKey:#"Product"];
self.DateTimeScanned = [decoder decodeObjectForKey:#"DateTimeScanned"];
self.Loaded = [decoder decodeBoolForKey:#"Loaded"];
}
return self;
}
My code to decode the object:
NSDictionary *tempDictionary = [[NSUserDefaults standardUserDefaults] dictionaryRepresentation];
NSArray *tempArray =[tempDictionary allKeys];
for (NSString *key in tempArray){
if ([key length] > 8) {
if ([[key substringToIndex:8] isEqualToString:#"INXITEM:"]) {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *encodedObject = [defaults objectForKey:key];
ScannedItem *SITemp = (ScannedItem *)[NSKeyedUnarchiver unarchiveObjectWithData:encodedObject];
}
}
}
Just found it...
It was because the property Loaded (bool) is a new property and the object that was saved in NSUserDefaults didn't contain that property.
Cleared my NSUserDefaults and everything is okay now...
You aren't calling the correct superclass method.
It should be
self = [super initWithCoder:decoder];
Try using - (void)encodeWithCoder:(NSCoder *)coder method in ScannedItem object class
- (void)encodeWithCoder:(NSCoder *)coder {
[coder encodeObject:self.SGTIN forKey:#"SGTIN"];
//encode all properties
}

Resources