iOS: Singleton returning null - ios

I have a singleton and I pass data to it but it returns null can you please help me in my situation. Thanks in advance :)
Here's my code
Card.h
#property (weak,nonatomic) NSString *email;
#property (weak,nonatomic) NSString *fName;
#property (weak,nonatomic) NSString *lName;
#property (weak,nonatomic) NSString *category;
+(Card *)getCard;
Card.m
#synthesize email;
#synthesize fName;
#synthesize lName;
#synthesize category;
static csCard *instance;
+(Card *) getCard
{
#synchronized (self)
{
if(instance == nil)
{
instance = [[Card alloc]init];
}
}
return instance;
}
- (id) init{
self.email = [[NSUserDefaults standardUserDefaults]stringForKey:#"email"];
self.fName = [[NSUserDefaults standardUserDefaults]stringForKey:#"firstName"];
self.lName = [[NSUserDefaults standardUserDefaults]stringForKey:#"lastName"];
self.category = #"TestCategory";
return self;
}
and here's my test code to see if it's working
Test.m
Card *card = [Card getCard];
[card setEmail:self.emailField.text];
NSLog(#"%#",card.email);
but this code give me (null)

Modify your class like this.
Card.h
#property (strong,nonatomic) NSString *email; //Let the modal be strong property
#property (strong,nonatomic) NSString *fName;
#property (strong,nonatomic) NSString *lName;
#property (strong,nonatomic) NSString *category;
+(Card *)getCard;
Card.m
static Card *instance;
+(Card *) getCard
{
#synchronized (self)
{
if(instance == nil)
{
instance = [[Card alloc]init];
}
}
return instance;
}
- (NSString)email{
return [[NSUserDefaults standardUserDefaults]stringForKey:#"email"];
}
- (void)setEmail:(NSString)email{
[[NSUserDefaults standardUserDefaults] setString:email forkey:#"email"];
}
No need of overriding init
in your test class
Card *card = [Card getCard];
[card setEmail:self.emailField.text];
NSLog(#"%#",card.email);

static csCard *instance;
+(csCard *) getCard
{
#synchronized (self)
{
if(instance == nil)
{
instance = [[csCard alloc]init];
}
}
return instance;
}
Replace it with this code
static Card *instance;
+(Card *) getCard
{
#synchronized (self)
{
if(instance == nil)
{
instance = [[Card alloc]init];
}
}
return instance;
}
The Class name Of the instance Object was wrong and In singleton method,the return datatype was also wrong. I think u will understand what I am saying.

+ (Card *)instance {
static Card *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[Card alloc] init];
});
return sharedInstance;
}
It should be work

With the help of what βhargavḯ sujjested u can modify your code as below because
in the line static csCard *instance; u are using csCard i think it is typo so better u can do like this,
#import "Card.h"
static dispatch_once_t onceDispach;
#implementation Card
#synthesize email = _email;
#synthesize fName;
#synthesize lName;
#synthesize category;
static Card *instance = nil; //change this to Card because this instance which is of type Card
+(Card *)getCard
{
dispatch_once(&onceDispach, ^{
instance = [[self alloc] init];//careate Card shared object named instance
});
return instance;
}
- (id) init
{
self.email = [[NSUserDefaults standardUserDefaults]stringForKey:#"email"];
self.fName = [[NSUserDefaults standardUserDefaults]stringForKey:#"firstName"];
self.lName = [[NSUserDefaults standardUserDefaults]stringForKey:#"lastName"];
self.category = #"TestCategory";
return self;
}
#end
- (NSString *)email
{
return _email;
}
- (void)setEmail:(NSString *)email
{
_email = email;
NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults];
[userDefault setObject:email forKey:#"email"];
}
in the class where u are using this shared instance use like below
- (void)actionMathodCalled
{
Card *card = [Card getCard];
NSLog(#"before saving to defaults->%#",card.email);
[card setEmail:#"happyCoding#ymail.com"];
NSLog(#"after savng to defaults->%#",card.email);
}

Related

How to share data between number of ViewControllers?

I know one way to share data is segue. But in my application I have multiple tabs which contain number of VCs. For instance userName and address. I want to show in some of the VCs these infos.
Every time I query the cloud is not right way. I am following this answer first part: answer. But as a newbie I am not sure how MyDataModel is defined. Is it a NSObject class? I appreciate if anyone can define this class as example with two NSString fields. And how to access these fields in VC and AppDelegate.
Inside AppDelegate
#interface MyAppDelegate : NSObject <UIApplicationDelegate, UITabBarControllerDelegate>
{
MyDataModel *model;
AViewController *aViewController;
BViewController *bViewController;
...
}
#property (retain) IBOutlet AViewController *aViewController;
#property (retain) IBOutlet BViewController *aViewController;
#end
#implementation MyAppDelegate
...
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
...
aViewController.model = model;
bViewController.model = model;
[window addSubview:tabBarController.view];
[window makeKeyAndVisible];
}
Inside VC:
#interface AViewController : UIViewController {
MyDataModel *model;
}
#property (nonatomic, retain) MyDataModel *model;
#end
#interface BViewController : UIViewController {
MyDataModel *model;
}
#property (nonatomic, retain) MyDataModel *model;
#end
The only thing I need is where to define MyDataMode and how to access its fields?
You can use singleton class for that,
----------
SharedManages.h
----------
#import <Foundation/Foundation.h>
#import "Reachability.h"
#import "Reachability.h"
#interface SharedManager : NSObject
{
}
+(SharedManager *)sharedInstance;
// Create property of your object which you want to access from whole over project.
#property (retain, nonatomic) User *loginUser;
#property (assign, readwrite) BOOL isNetAvailable;
#end
----------
----------
SharedManages.m
----------
#import "SharedManager.h"
static SharedManager *objSharedManager;
#implementation SharedManager
#synthesize
isNetAvailable = _isNetAvailable,
loginUser = _ loginUser;
+(SharedManager *)sharedInstance
{
if(objSharedManager == nil)
{
objSharedManager = [[SharedManager alloc] init];
objSharedManager. loginUser = [User alloc]] init];
Reachability *r = [Reachability reachabilityForInternetConnection];
NetworkStatus internetStatus = [r currentReachabilityStatus];
// Bool
if(internetStatus == NotReachable)
{
NSLog(#"Internet Disconnected");
objSharedManager.isNetAvailable = NO; // Internet not Connected
}
else if (internetStatus == ReachableViaWiFi)
{
NSLog(#"Connected via WIFI");
objSharedManager.isNetAvailable = YES; // Connected via WIFI
}
else if (internetStatus == ReachableViaWWAN)
{
NSLog(#"Connected via WWAN");
objSharedManager.isNetAvailable = YES; // Connected via WWAN
}
}
return objSharedManager;
}
#end
Access from other Class...
[SharedManager sharedInstance].isNetAvailable ;
[SharedManager sharedInstance].loginUser ;
Hope, This will help you..
I don't have "local" copies of the values. I set them in the delegate and fetch them from there. That way you don't have to hard code it for all UIViewController's in the delegate.
Assigning values is best done on the first view, or with default values. I personally use viewDidLoad for those kind of things. Since it is only called once on the first view once and pertains until the app is terminated.
Then I get the delegate from inside the VC, call the instance and from there the values.
Swift
Inside AppDelegate:
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var globals : GlobalValueClass?
First VC:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let delegate = UIApplication.sharedApplication().delegate as! AppDelegate
delegate.globals = GlobalValueClass()
delegate.globals!.numbers = [1,2,3]
}
}
Other VC's:
class ViewControllerTwo: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let delegate = UIApplication.sharedApplication().delegate as! AppDelegate
print(delegate.globals!.numbers)
// Do any additional setup after loading the view.
}
}
Objective C ( don't have the full method in obj-c, but easy to find)
MainClass *appDelegate = (MainClass *)[[UIApplication sharedApplication] delegate];
how to get the delegate in obj-c
Easiest way i could think of is using NSUserDefaults. Save your name and address string in NSUserDefaults like
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setValue:YourNameString forKey:#"NameString"];
[defaults setValue:YourAddressString forKey:#"AddressString"];
[defaults synchronize];
and access it in any ViewController as
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *name = [plistContent valueForKey:#"NameString"];
NSString *address= [plistContent valueForKey:#"AddressString"];
Hope this helps.
You can create a class and use it in your tab controller.
#import <Foundation/Foundation.h>
#interface UserModel : NSObject <NSCoding>
#property (nonatomic, strong) NSString *lastName;
#property (nonatomic, strong) NSString *firstName;
+ (instancetype)modelObjectWithDictionary:(NSDictionary *)dict;
- (instancetype)initWithDictionary:(NSDictionary *)dict;
- (NSDictionary *)dictionaryRepresentation;
#end
implementation file
#import "UserModel.h"
NSString *const kUserModelLastName = #"LastName";
NSString *const kUserModelFirstName = #"FirstName";
#interface UserModel ()
- (id)objectOrNilForKey:(id)aKey fromDictionary:(NSDictionary *)dict;
#end
#implementation UserModel
#synthesize lastName = _lastName;
#synthesize firstName = _firstName;
+ (instancetype)modelObjectWithDictionary:(NSDictionary *)dict
{
return [[self alloc] initWithDictionary:dict];
}
- (instancetype)initWithDictionary:(NSDictionary *)dict
{
self = [super init];
// This check serves to make sure that a non-NSDictionary object
// passed into the model class doesn't break the parsing.
if(self && [dict isKindOfClass:[NSDictionary class]]) {
self.lastName = [self objectOrNilForKey:kUserModelLastName fromDictionary:dict];
self.firstName = [self objectOrNilForKey:kUserModelFirstName fromDictionary:dict];
}
return self;
}
- (NSDictionary *)dictionaryRepresentation
{
NSMutableDictionary *mutableDict = [NSMutableDictionary dictionary];
[mutableDict setValue:self.lastName forKey:kUserModelLastName];
[mutableDict setValue:self.firstName forKey:kUserModelFirstName];
return [NSDictionary dictionaryWithDictionary:mutableDict];
}
- (NSString *)description
{
return [NSString stringWithFormat:#"%#", [self dictionaryRepresentation]];
}
#pragma mark - Helper Method
- (id)objectOrNilForKey:(id)aKey fromDictionary:(NSDictionary *)dict
{
id object = [dict objectForKey:aKey];
return [object isEqual:[NSNull null]] ? nil : object;
}
#pragma mark - NSCoding Methods
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super init];
self.lastName = [aDecoder decodeObjectForKey:kUserModelLastName];
self.firstName = [aDecoder decodeObjectForKey:kUserModelFirstName];
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:_lastName forKey:kUserModelLastName];
[aCoder encodeObject:_firstName forKey:kUserModelFirstName];
}
Import this class where you are setting or initializing data or values. and do below code.
NSDictionary *dicUserModel = [[NSDictionary alloc]initWithObjectsAndKeys:#"Moure",#"LastName",#"Jackson",#"FirstName", nil];
UserModel *userModel = [[UserModel alloc]initWithDictionary:dicUserModel];
//NSUserDefault save your class with all property. and you can simply retrieve your UserModel from NSUserDefault.
//Below code save this model into nsuserdefault.
[[NSUserDefaults standardUserDefaults]setObject:[NSKeyedArchiver archivedDataWithRootObject:userModel] forKey:#"UserModel"];
[[NSUserDefaults standardUserDefaults]synchronize];
You can retrieve you class object using below code.
UserModel *savedUserModel = (UserModel *)[NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults]objectForKey:#"UserModel"]];
NSLog(#"%#",savedUserModel.firstName);
NSLog(#"%#",savedUserModel.lastName);

Trouble setting long value in singleton IOS

I'm having trouble with setting and accessing long properties on a Singleton object. Every time I try to access a long property it returns -1.
My singleton interface file is as follows:
#interface gameData : NSObject <NSCoding>
#property (assign, nonatomic) long score;
#property (assign, nonatomic) long level;
#property (assign, nonatomic) long riddlesCompleted;
#property (assign, nonatomic) long hints;
#property (assign, nonatomic) long firstLetters;
#property (assign, nonatomic) long answers;
+(instancetype)sharedGameData;
-(void)reset;
-(void)save;
#end
Then the implementation file sets up the encoders and decoders as follows:
-(void)encodeWithCoder:(NSCoder *)aCoder{
[aCoder encodeDouble:self.score forKey:gameDataScoreKey];
[aCoder encodeDouble:self.level forKey:gameDataLevelKey];
[aCoder encodeDouble:self.riddlesCompleted forKey:gameDataRiddlesCompletedKey];
[aCoder encodeDouble:self.hints forKey:gameDataHintsKey];
[aCoder encodeDouble:self.firstLetters forKey:gameDataFirstLettersKey];
[aCoder encodeDouble:self.answers forKey:gameDataAnswersKey];
}
-(instancetype)initWithCoder:(NSCoder *)decoder{
self = [self init];
if (self) {
_score = [decoder decodeDoubleForKey:gameDataScoreKey];
_level = [decoder decodeDoubleForKey:gameDataLevelKey];
_riddlesCompleted = [decoder decodeDoubleForKey:gameDataRiddlesCompletedKey];
_hints = [decoder decodeDoubleForKey:gameDataHintsKey];
_firstLetters = [decoder decodeDoubleForKey:gameDataFirstLettersKey];
_answers = [decoder decodeDoubleForKey:gameDataAnswersKey];
}
return self;
}
+(instancetype) sharedGameData{
static id sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [self loadInstance];
});
return sharedInstance;
}
Values are initialised as follows:
-(id)init{
if(self = [super init]){
_score = 500;
_riddlesCompleted = 0;
_level = 1;
_hints = 3;
_firstLetters = 3;
_answers = 3;
}
return self;
}
and then the instance is loaded:
+(NSString*)filePath{
static NSString* filePath = nil;
if (!filePath) {
filePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask, YES) firstObject]
stringByAppendingString:#"gameData"];
}
return filePath;
}
+(instancetype)loadInstance{
NSData* decodeData = [NSData dataWithContentsOfFile:[gameData filePath]];
if (decodeData) {
gameData* gameData = [NSKeyedUnarchiver unarchiveObjectWithData:decodeData];
return gameData;
}
return [[gameData alloc] init];
}
Then elsewhere in the application when I try to access these values I am not able to access the values of hints, firstletters or answers.
If I try logging the values as follows:
NSLog([NSString stringWithFormat:#"%li", [gameData sharedGameData].score] );
NSLog([NSString stringWithFormat:#"%li", [gameData sharedGameData].hint] );
NSLog([NSString stringWithFormat:#"%li", [gameData sharedGameData].answers]);
NSLog([NSString stringWithFormat:#"%li", [gameData sharedGameData].firstLetters]);
The output I get is 500 for score but for all the others I get 0 even though they are initialised in the gameData.m file with values 3.
Just a guess:
In loadInstance() you read the values from the file, so if there is a file you won't get in the init() where you set the values.
To be sure there is no gamedata-file you should reset the simulator oder delete the app from the device and try again.

Variable returning unexpected 0 in xcode

The variable 'bubbleBankCapacity' is expected to return as 500 and be compared to the 'regularBubbleCount' variable in the comparison below, but instead returns as 0 which effectively makes the condition false given that the regularBubbleCount is greater than 0. Why is this returning a 0 when it has been set to initialize as 500?
AppDelegate.m
#import "AppDelegate.h"
#interface AppDelegate ()
#end
#implementation AppDelegate
-(void)timerCalled
{
NSLog(#"Timer Called");
if ([RWGameData sharedGameData].bubbleFactoryUpgradeTier > 0) {
if ([RWGameData sharedGameData].regularBubbleCount < [RWGameData sharedGameData].bubbleBankCapacity) {
NSLog(#"bubbleFactoryUpgradeTier: %li", [RWGameData sharedGameData].bubbleFactoryUpgradeTier);
[RWGameData sharedGameData].regularBubbleCount += [RWGameData sharedGameData].bubbleFactoryTickValue;
NSLog(#"bubbleFactoryTickValue: %i", [RWGameData sharedGameData].bubbleFactoryTickValue);
[[RWGameData sharedGameData] save];
} else {
NSLog(#"Capacity Reached! Capacity: %li", [RWGameData sharedGameData].bubbleBankCapacity);
}
} NSLog(#"Regular Bubble Count: %li", [RWGameData sharedGameData].regularBubbleCount);
}
RWGameData.h
#import <Foundation/Foundation.h>
#interface RWGameData : NSObject <NSCoding>
#property (assign, nonatomic) long regularBubbleCount;
#property (assign, nonatomic) long premiumBubbleCount;
#property (assign, nonatomic) long megaBubbleUpgradeTier;
#property (assign, nonatomic) long bubbleFactoryUpgradeTier;
#property (assign, nonatomic) long bubblersUpgradeTier;
#property (assign, nonatomic) long mysteryBubbleUpgradeTier;
#property (assign, nonatomic) long bubbleBankUpgradeTier;
#property (assign, nonatomic) int megaBubblePopValue;
#property (assign, nonatomic) int bubbleFactoryTickValue;
#property (assign, nonatomic) long bubbleBankCapacity;
+(instancetype)sharedGameData;
-(void)reset;
-(void)save;
#end
RWGameData.m
#import "RWGameData.h"
#implementation RWGameData
static NSString* const SSGameDataRegularBubbleCountKey = #"regularBubbleCount";
static NSString* const SSGameDataPremiumBubbleCountKey = #"premiumBubbleCount";
static NSString* const SSGameDataMegaBubbleUpgradeTierKey = #"megaBubbleUpgradeTier";
static NSString* const SSGameDataBubbleFactoryUpgradeTierKey = #"bubbleFactoryUpgradeTier";
static NSString* const SSGameDataBubblersUpgradeTierKey = #"bubblersUpgradeTier";
static NSString* const SSGameDataMysteryBubbleUpgradeTierKey = #"mysteryBubbleUpgradeTier";
static NSString* const SSGameDataBubbleBankUpgradeTierKey = #"bubbleBankUpgradeTier";
static NSString* const SSGameDataMegaBubblePopValueKey = #"megaBubblePopValueKey";
static NSString* const SSGameDataBubbleFactoryTickValueKey = #"bubbleFactoryTickValueKey";
static NSString* const SSGameDataBubbleBankCapacityKey = #"bubbleBankCapacityKey";
+ (instancetype)sharedGameData {
static id sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [self loadInstance];
});
return sharedInstance;
}
-(void)reset {
self.regularBubbleCount = 0;
self.premiumBubbleCount = 0;
self.megaBubbleUpgradeTier = 0;
self.bubbleFactoryUpgradeTier = 0;
self.bubblersUpgradeTier = 0;
self.mysteryBubbleUpgradeTier = 0;
self.bubbleBankUpgradeTier = 0;
self.megaBubblePopValue = 1;
self.bubbleFactoryTickValue = 1;
self.bubbleBankCapacity = 500;
}
- (void)encodeWithCoder:(NSCoder *)encoder
{
[encoder encodeDouble:self.regularBubbleCount forKey: SSGameDataRegularBubbleCountKey];
[encoder encodeDouble:self.premiumBubbleCount forKey: SSGameDataPremiumBubbleCountKey];
[encoder encodeDouble:self.megaBubbleUpgradeTier forKey: SSGameDataMegaBubbleUpgradeTierKey];
[encoder encodeDouble:self.bubbleFactoryUpgradeTier forKey: SSGameDataBubbleFactoryUpgradeTierKey];
[encoder encodeDouble:self.bubblersUpgradeTier forKey: SSGameDataBubblersUpgradeTierKey];
[encoder encodeDouble:self.mysteryBubbleUpgradeTier forKey: SSGameDataMysteryBubbleUpgradeTierKey];
[encoder encodeDouble:self.bubbleBankUpgradeTier forKey: SSGameDataBubbleBankUpgradeTierKey];
[encoder encodeDouble:self.megaBubblePopValue forKey: SSGameDataMegaBubblePopValueKey];
[encoder encodeDouble:self.bubbleFactoryTickValue forKey: SSGameDataBubbleFactoryTickValueKey];
[encoder encodeDouble:self.bubbleBankCapacity forKey: SSGameDataBubbleBankCapacityKey];
}
- (instancetype)initWithCoder:(NSCoder *)decoder
{
self = [self init];
if (self) {
_regularBubbleCount = [decoder decodeDoubleForKey: SSGameDataRegularBubbleCountKey];
_premiumBubbleCount = [decoder decodeDoubleForKey: SSGameDataPremiumBubbleCountKey];
_megaBubbleUpgradeTier = [decoder decodeDoubleForKey: SSGameDataMegaBubbleUpgradeTierKey];
_bubbleFactoryUpgradeTier = [decoder decodeDoubleForKey: SSGameDataBubbleFactoryUpgradeTierKey];
_bubblersUpgradeTier = [decoder decodeDoubleForKey: SSGameDataBubblersUpgradeTierKey];
_mysteryBubbleUpgradeTier = [decoder decodeDoubleForKey: SSGameDataMysteryBubbleUpgradeTierKey];
_bubbleBankUpgradeTier = [decoder decodeDoubleForKey: SSGameDataBubbleBankUpgradeTierKey];
_megaBubblePopValue = [decoder decodeDoubleForKey: SSGameDataMegaBubblePopValueKey];
_bubbleFactoryTickValue = [decoder decodeDoubleForKey: SSGameDataBubbleFactoryTickValueKey];
_bubbleBankCapacity = [decoder decodeDoubleForKey: SSGameDataBubbleBankCapacityKey];
}
return self;
}
+(NSString*)filePath
{
static NSString* filePath = nil;
if (!filePath) {
filePath =
[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]
stringByAppendingPathComponent:#"gamedata"];
}
return filePath;
}
+(instancetype)loadInstance
{
NSData* decodedData = [NSData dataWithContentsOfFile: [RWGameData filePath]];
if (decodedData) {
RWGameData* gameData = [NSKeyedUnarchiver unarchiveObjectWithData:decodedData];
return gameData;
}
return [[RWGameData alloc] init];
}
-(void)save
{
NSData* encodedData = [NSKeyedArchiver archivedDataWithRootObject: self];
[encodedData writeToFile:[RWGameData filePath] atomically:YES];
}
#end
You need to initialize the bubbleBankCapacity variable in AppDelegate.m inside your method.
Solved.
I went ahead and declared a boolean property to RWGameData and tasked the reset method to set it to true when the reset method had been called. Then I went ahead and adjusted - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions like so:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
if (![RWGameData sharedGameData].dataIsInitialized) {
[[RWGameData sharedGameData] reset];
}
NSTimer *timer;
timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(timerCalled) userInfo:nil repeats:YES];
return YES;
}
Thank you to everyone who offered a solution to this problem. I greatly appreciate it!

NSCache is returning null after restarting project

I'm working with NSCache in Objective-C and Cocoa for iOS. Every time I restart the project, the getCacheRecommend call returns null and I expect it to return a value.
#import <Foundation/Foundation.h>
#class ASJsonDiscoverModel;
#interface ASUserCache : NSObject
+ (ASUserCache *)sharedInstance;
- (void)clear;
- (void)setCacheRecommend:(ASJsonDiscoverModel *)discover;
- (ASJsonDiscoverModel *)getCacheRecommend;
ASJsonDiscoverModel is my custom object class.
#import "ASUserCache.h"
#interface ASUserCache ()
#property (nonatomic,strong) NSCache *cache;
#end
#implementation ASUserCache
+ (ASUserCache *)sharedInstance
{
__strong static ASUserCache *cache = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
cache = [[ASUserCache alloc] init];
});
return cache;
}
- (instancetype)init
{
if (self = [super init]) {
_cache = [[NSCache alloc] init];
}
return self;
}
- (void)setCacheRecommend:(ASJsonDiscoverModel *)discover
{
NSString *key = #"channelRecommend";
[_cache removeObjectForKey:key];
[_cache setObject:discover forKey:key];
}
- (ASJsonDiscoverModel *)getCacheRecommend
{
NSString *key = #"channelRecommend";
return [_cache objectForKey:key];
}
- (void)clear
{
if (_cache) {
[_cache removeAllObjects];
}
}
- (NSString *)keyforUserID:(NSString *)userID
{
return [NSString stringWithFormat:#"**%#",userID];
}

Saving NSDictionary (with custom classes) to NSUserDefaults [duplicate]

This question already has answers here:
How to store custom objects in NSUserDefaults
(7 answers)
Closed 9 years ago.
I am trying to save an NSDictionary to my NSUserDefualts.
The dictionary consists of 3 different custom classes.
#interface PastOrder : NSObject <NSCoding>
{
NSDate *timeIn;
NSDate *timeOut;
NSString *status;
NSMutableArray *myItems;
}
#property (nonatomic, retain) NSDate *timeIn;
#property (nonatomic, retain) NSDate *timeOut;
#property (nonatomic, retain) NSString *status;
#property (nonatomic, retain) NSMutableArray *myItems;
#end
#implementation PastOrder
#synthesize timeIn, timeOut, status, myItems;
#define PastOrderTimeInKey #"PastOrderTimeInKey"
#define PastOrderTimeOutKey #"PastOrderTimeOutKey"
#define PastOrderStatusKey #"PastOrderStatusKey"
#define PastOrderMyItemsKey #"PastOrderMyItemsKey"
-(id)initWithCoder:(NSCoder*)decoder
{
self = [super init];
if(self)
{
self.timeIn = [decoder decodeObjectForKey:PastOrderTimeInKey];
self.timeOut = [decoder decodeObjectForKey:PastOrderTimeOutKey];
self.status = [decoder decodeObjectForKey:PastOrderStatusKey];
self.myItems = [decoder decodeObjectForKey:PastOrderMyItemsKey];
}
return self;
}
-(void)encodeWithCoder:(NSCoder*)encoder
{
[encoder encodeObject:self.timeIn forKey:PastOrderTimeInKey];
[encoder encodeObject:self.timeOut forKey:PastOrderTimeOutKey];
[encoder encodeObject:self.status forKey:PastOrderStatusKey];
[encoder encodeObject:self.myItems forKey:PastOrderMyItemsKey];
}
-(void)dealloc
{
self.timeIn = nil;
self.timeOut = nil;
self.status = nil;
self.myItems = nil;
}
#end
#interface PastOrderItem : NSObject <NSCoding>
{
NSNumber *itemID;
NSString *status;
NSMutableArray *itemChoices;
}
#property (nonatomic, retain) NSNumber *itemID;
#property (nonatomic, retain) NSString *status;
#property (nonatomic, retain) NSMutableArray *itemChoices;
#end
#implementation PastOrderItem
#synthesize itemID,status,itemChoices;
#define PastOrderItemItemIDKey #"PastOrderItemItemIDKey"
#define PastOrderItemStatusKey #"PastOrderItemStatusKey"
#define PastOrderItemItemChoicesKey #"PastOrderItemItemChoicesKey"
-(id)initWithCoder:(NSCoder*)decoder
{
self = [super init];
if(self)
{
self.itemID = [decoder decodeObjectForKey:PastOrderItemItemIDKey];
self.itemChoices = [decoder decodeObjectForKey:PastOrderItemItemChoicesKey];
self.status = [decoder decodeObjectForKey:PastOrderItemStatusKey];
}
return self;
}
-(void)encodeWithCoder:(NSCoder*)encoder
{
[encoder encodeObject:self.itemID forKey:PastOrderItemItemIDKey];
[encoder encodeObject:self.itemChoices forKey:PastOrderItemItemChoicesKey];
[encoder encodeObject:self.status forKey:PastOrderItemStatusKey];
}
-(void)dealloc
{
self.itemID = nil;
self.itemChoices = nil;
self.status = nil;
}
#end
#interface PastOrderItemChoice : NSObject <NSCoding>
{
NSNumber *modifierID;
NSNumber *modifierChoice;
}
#property (nonatomic, retain) NSNumber *modifierID;
#property (nonatomic, retain) NSNumber *modifierChoice;
#end
#implementation PastOrderItemChoice
#synthesize modifierID, modifierChoice;
#define PastOrderItemChoiceModifierIDKey #"PastOrderItemChoiceModifierIDKey"
#define PastOrderItemChoiceModifierChoiceKey #"PastOrderItemChoiceModifierChoiceKey"
-(id)initWithCoder:(NSCoder*)decoder
{
self = [super init];
if(self)
{
self.modifierID = [decoder decodeObjectForKey:PastOrderItemChoiceModifierIDKey];
self.modifierChoice = [decoder decodeObjectForKey:PastOrderItemChoiceModifierChoiceKey];
}
return self;
}
-(void)encodeWithCoder:(NSCoder*)encoder
{
[encoder encodeObject:self.modifierID forKey:PastOrderItemChoiceModifierIDKey];
[encoder encodeObject:self.modifierChoice forKey:PastOrderItemChoiceModifierChoiceKey];
}
-(void)dealloc
{
self.modifierID = nil;
self.modifierChoice = nil;
}
#end
Those are the three classes that will be inside this NSDictionary.
Here is how I Load and Save it.
-(void)SavePrefs
{
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
NSData* data=[NSKeyedArchiver archivedDataWithRootObject:self.myDictionary];
[prefs setObject:data forKey:#"SavedOrders"];
[prefs synchronize];
}
- (id)init
{
self = [super init];
if (self)
{
NSData* data = [[NSUserDefaults standardUserDefaults] objectForKey:#"SavedOrders"];
self.myDictionary = [NSKeyedUnarchiver unarchiveObjectWithData:data];
}
return self;
}
I have experimented with the code a bit, and best I have to far, is that when I save the dictionary, it was 135 bytes, same as when I loaded it, but it still didnt fill the dictionary up. So I am at a loss.
Your code seems to be good. I can't find a mistake so try to change line:
self.myDictionary = [NSKeyedUnarchiver unarchiveObjectWithData:data];
to
id unknownObject = [NSKeyedUnarchiver unarchiveObjectWithData:data];
NSLog(#"%#",[unknownObject class]);
And look # the console. Maybe you should also try casting if the output will be dictionary. So try to change this to:
self.myDictionary = (NSDictionary*)[NSKeyedUnarchiver unarchiveObjectWithData:data];
EDIT
NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:#"object1",#"key1",#"object2",#"key2",#"object3",#"key3", nil];
NSLog(#"before: %#",dictionary);
NSData *myData = [NSKeyedArchiver archivedDataWithRootObject:dictionary];
NSDictionary *myDictionary = (NSDictionary*) [NSKeyedUnarchiver unarchiveObjectWithData:myData];
NSLog(#"after: %#",myDictionary);
Output:
2013-11-13 14:32:31.369 DemoM[175:60b] before: {
key1 = object1;
key2 = object2;
key3 = object3;
}
2013-11-13 14:32:31.372 DemoM[175:60b] after: {
key1 = object1;
key2 = object2;
key3 = object3;
}

Resources