NSCache is returning null after restarting project - ios

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];
}

Related

access objects from Bluetooth manager using singleton in ios

I am trying to create a singleton class for my BLEManager which gets called on viewdidload of the launch screen ViewController. How can I get the objects _transporter and _BLEAdapter in my view controller after the init is completed?
BLEManager.h
#interface MyManager : NSObject {
BLETransporter* _transporter;
BLEAdapter* _BLEAdapter;
}
#property (strong, nonatomic) BLETransporter* transporter;
#property (strong, nonatomic) BLEAdapter* BLEAdapter;
+ (id)sharedInstance;
#end
BLEManager.m
#implementation MyManager
#synthesize BLEAdapter=_BLEAdapter;
#synthesize transporter = _BLEAdapter;
+(BLEManager*)sharedInstance{
static BLEManager *sharedInstance = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
- (id)init {
if (self = [super init]) {
_transporter = [BLETransporter transporterWithIdentifier:nil serviceUUIDs:serviceUUIDs];
[_transporter connectWithBlock:^(NSInputStream * _Nullable inputStream, NSOutputStream * _Nullable outputStream) {
if ( !inputStream )
{
LOG( #"Could not connect to device" );
return;
}
_BLEAdapter = [BLEAdapter adapterWithInputStream:inputStream outputStream:outputStream];
[_BLEAdapter connect];
}];
}
return self
}

Objective-C Defining a Global Array for use by several ViewControllers

I've been trying to implement a global NSMutableArray from what I think to be a singleton class that I've implemented.
I can enter ViewController # 2, add and remove objects to the array.
However, when I leave ViewController #2 and come back, the data does not persist, and I have an array with 0 objects.
What do you think I'm doing wrong?
.h
// GlobalArray.h
#interface GlobalArray : NSObject{
NSMutableArray* globalArray;
}
+(void)initialize;
.m
#import "GlobalArray.h"
#implementation GlobalArray
static GlobalArray* sharedGlobalArray;
NSMutableArray* globalArray;
+(void)initialize{
static BOOL initalized = NO;
if(!initalized){
initalized = YES;
sharedGlobalArray = [[GlobalArray alloc] init];
}
}
- (id)init{
if (self = [super init]) {
if (!globalArray) {
globalArray = [[NSMutableArray alloc] init];
}
}
return self;
}
View Controller #2
GlobalArray* myGlobalArray;
myGlobalArray = [[GlobalArray alloc] init];
//Various add and remove code
Thank you for your input.
Following is best approach to share data Globally at Application level. Singleton Class is a key. Singleton is only initialised once, rest of times shared data is returned.
#interface Singleton : NSObject
#property (nonatomic, retain) NSMutableArray * globalArray;
+(Singleton*)singleton;
#end
#implementation Singleton
#synthesize globalArray;
+(Singleton *)singleton {
static dispatch_once_t pred;
static Singleton *shared = nil;
dispatch_once(&pred, ^{
shared = [[Singleton alloc] init];
shared.globalArray = [[NSMutableArray alloc]init];
});
return shared;
}
#end
Following is the way to access/use shared data.
NSMutableArray * sharedData = [Singleton singleton].globalArray;
You create separate instance of GlobalArray in your ViewController#2 with this code:
GlobalArray* myGlobalArray;
myGlobalArray = [[GlobalArray alloc] init];
Instead, you should create accessor method to return your shared instance, something like this:
// GlobalArray.h
#interface GlobalArray : NSObject{
NSMutableArray* globalArray;
}
+(void)initialize;
+(GlobalArray*)sharedInstance;
with implementation:
// GlobalArray.m
// ... your existing code
// accessor method
+(GlobalArray*)sharedInstance
{
return sharedGlobalArray;
}
and then call it from your ViewController#2:
GlobalArray* myGlobalArray = [GlobalArray sharedInstance];
However, using global variables to transfer data between view controllers is bad practice; I suggest you to use more safe methods, create a delegate, for example.
To create a shared global array, if that's really what you want, just put this in the header file:
extern NSMutableArray *myGlobalArray;
and this in your main source file:
NSMutableArray *myGlobalArray;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
myGlobalArray = [NSMutableArray new];
}
Use this code for set and get the array views, for adding and removing do it separate in controller itself.
// GlobalArray.h
#interface GlobalArray : NSObject
#property (nonatomic, strong) NSMutableArray* globalArray;
+ (id)sharedManager;
-(NSMutableArray *) getGlobalArray;
-(void) setGlobalArray:(NSMutableArray *)array;
#end
/*-----------------------------------------*/
#import "GlobalArray.h"
#implementation GlobalArray
+ (id)sharedManager {
static GlobalArray *sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] init];
});
return sharedMyManager;
}
- (id)init{
if (self = [super init]) {
if (!globalArray) {
globalArray = [[NSMutableArray alloc] init];
}
}
return self;
}
-(NSMutableArray *) getGlobalArray{
return self.globalArray;
}
-(void) setGlobalArray:(NSMutableArray *)array{
_globalArray = globalArray;
}
#end
-------------------------
//get array
NSArray * array = [[GlobalArray sharedManager] getGlobalArray];
//set array
[[GlobalArray sharedManager] setGlobalArray:array]
-------------------------

How to add object in singleton NSMutableArray

I used to store the array data downloaded from the server.
But I can not save them in the singleton array.
It seems without access to the object.
Why ulatitude, ulongitude, uaccuracy, uplacename is nil?...
in .h file
#import <Foundation/Foundation.h>
#interface LocationData : NSObject
{
NSMutableArray *ulatitude;
NSMutableArray *ulongitude;
NSMutableArray *uaccuracy;
NSMutableArray *uplacename;
}
#property (nonatomic, retain) NSMutableArray *ulatitude;
#property (nonatomic, retain) NSMutableArray *ulongitude;
#property (nonatomic, retain) NSMutableArray *uaccuracy;
#property (nonatomic, retain) NSMutableArray *uplacename;
+ (LocationData*) sharedStateInstance;
#end
in .m file
#import "LocationData.h"
#implementation LocationData
#synthesize uaccuracy;
#synthesize ulatitude;
#synthesize ulongitude;
+ (LocationData*) sharedStateInstance {
static LocationData *sharedStateInstance;
#synchronized(self) {
if(!sharedStateInstance) {
sharedStateInstance = [[LocationData alloc] init];
}
}
return sharedStateInstance;
}
#end
use
[manager POST:urlStr parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSLog(#"%#",responseObject);
// json response array
if ([responseObject isKindOfClass:[NSArray class]]) {
NSArray *responseArray = responseObject;
NSDictionary *responseDict = [[NSDictionary alloc] init];
LocationData* sharedState = [LocationData sharedStateInstance];
for(NSUInteger i=0; i < responseArray.count; i++)
{
responseDict = [responseArray objectAtIndex:i];
double dlat = [[responseDict objectForKey:#"lat"] doubleValue];
double dlng = [[responseDict objectForKey:#"lng"] doubleValue];
[[sharedState ulatitude] addObject:[NSString stringWithFormat:#"%f",dlat]];
[[sharedState ulongitude] addObject:[NSString stringWithFormat:#"%f",dlng]];
[[sharedState uaccuracy] addObject:[responseDict objectForKey:#"rad"]];
[[sharedState uplacename] addObject:[responseDict objectForKey:#"place_name"]];
}
You always need to initialize your arrays. You should do somewhere before you try to add something to them:
arrayName = [[NSMutableArray alloc] init];
otherwise you'll always get error because they have not been initialized.
In your case you should override your LocationData init function like this:
- (instancetype)init {
self = [super init];
if (self) {
self.yourArrayName = [[NSMutableArray alloc] init];
// And so on....
}
return self;
}
You need to initialize your object properly. Basically your member variables ("ivars") are pointing to nothing ("nil").
This initializer added to your .m file code do the job.
-(instancetype)init {
if ((self = [super init])) {
self.accuracy = [NSMutableArray array];
self.latitude = [NSMutableArray array];
self.longitude = [NSMutableArray array];
self.uplacename = [NSMutableArray array];
}
return self;
}
As a singleton pattern, I'd prefer the following:
+ (LocationData*) sharedStateInstance {
static LocationData *sharedStateInstance = nil;
static dispatch_once_t onceToken = 0;
dispatch_once(&onceToken, ^{
sharedStateInstance = [[LocationData alloc] init];
});
return sharedStateInstance;
}
Although singletons might not be as bad they are often said to be, I don't thing that this is a good usage for them. Your specific problem has nothing to do with that design choice, though.
Try this code. Write getters for your NSMutableArrays.
#import <Foundation/Foundation.h>
#interface LocationData : NSObject
#property (nonatomic, retain) NSMutableArray *ulatitude;
#property (nonatomic, retain) NSMutableArray *ulongitude;
#property (nonatomic, retain) NSMutableArray *uaccuracy;
#property (nonatomic, retain) NSMutableArray *uplacename;
+ (LocationData*) sharedStateInstance;
#end
#import "LocationData.h"
#implementation LocationData
#synthesize uaccuracy = _uaccuracy;
#synthesize ulatitude = _ulatitude;
#synthesize ulongitude = _ulongitude;
+ (LocationData*) sharedStateInstance {
static LocationData *sharedStateInstance;
#synchronized(self) {
if(!sharedStateInstance) {
sharedStateInstance = [[LocationData alloc] init];
}
}
return sharedStateInstance;
}
-(NSMutableArray*)uaccuracy
{
if(_uaccuracy == nil)
{
_uaccuracy = [[NSMutableArray alloc]init];
}
return uaccuracy;
}
-(NSMutableArray*)ulongitude
{
if(_ulongitude == nil)
{
_ulongitude = [[NSMutableArray alloc]init];
}
return ulongitude;
}
-(NSMutableArray*)ulatitude
{
if(_ulatitude == nil)
{
_ulatitude = [[NSMutableArray alloc]init];
}
return ulatitude;
}
-(NSMutableArray*)uplacename
{
if(_uplacename == nil)
{
_uplacename = [[NSMutableArray alloc]init];
}
return uplacename;
}
#end
you don't allocate/init any array...
you can create them in your singleton creation method
+ (LocationData*) sharedStateInstance {
static LocationData *sharedStateInstance;
#synchronized(self) {
if(!sharedStateInstance) {
sharedStateInstance = [[LocationData alloc] init];
sharedStateInstance.ulatitude = [[NSMutableArray alloc] init];
// (add others...)
}
}
return sharedStateInstance;
}
Replace your LocationData.m file with below code , this will work . As you have to alloc and init the array then only you can add object in array
+ (LocationData*) sharedStateInstance {
static LocationData *sharedStateInstance;
#synchronized(self) {
if(!sharedStateInstance) {
sharedStateInstance = [[LocationData alloc] init];
uaccuracy = [[NSMutableArray alloc]init];
ulatitude = [[NSMutableArray alloc]init];
ulongitude = [[NSMutableArray alloc]init];
uplacename = [[NSMutableArray alloc]init];
}
}
return sharedStateInstance;
}

iOS: Singleton returning null

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);
}

Singleton NSMutableDictionary property won't allow setObject:forKey

I have a complete noob question for you. I'm obviously rusty with obj-c. I have a simple shopping cart class implemented as a singleton and just want it to store a single NSMutableDictionary. I want to be able to add objects to this dictionary from anywhere in the app. But for some (I'm sure simple) reason it's just returning null. No error messages.
ShoppingCart.h:
#import <Foundation/Foundation.h>
#interface ShoppingCart : NSObject
// This is the only thing I'm storing here.
#property (nonatomic, strong) NSMutableDictionary *items;
+ (ShoppingCart *)sharedInstance;
#end
ShoppingCart.m:
// Typical singelton.
#import "ShoppingCart.h"
#implementation ShoppingCart
static ShoppingCart *sharedInstance = nil;
+ (ShoppingCart *)sharedInstance
{
#synchronized(self)
{
if (sharedInstance == nil)
sharedInstance = [[self alloc] init];
}
return(sharedInstance);
}
#end
And in my VC I'm trying to set it with:
- (IBAction)addToCartButton:(id)sender
{
NSDictionary *thisItem = [[NSDictionary alloc] initWithObjects:#[#"test", #"100101", #"This is a test products description"] forKeys:#[#"name", #"sku", #"desc"]];
// This is what's failing.
[[ShoppingCart sharedInstance].items setObject:thisItem forKey:#"test"];
// But this works.
[ShoppingCart sharedInstance].items = (NSMutableDictionary *)thisItem;
// This logs null. Specifically "(null) has been added to the cart"
DDLogCInfo(#"%# has been added to the cart", [[ShoppingCart sharedInstance] items]);
}
Thanks
You are never creating a NSMutableDictionary object named items.
You could create it in the init of ShoppingCart.
-(id)init
{
if(self = [super init]) {
_items = [NSMutableDictionary dictionary];
}
return self;
}
or in sharedInstance
+ (ShoppingCart *)sharedInstance
{
#synchronized(self)
{
if (sharedInstance == nil)
sharedInstance = [[self alloc] init];
sharedInstance.items = [NSMutableDictionary dictionary];
}
return(sharedInstance);
}
I might also add it's better (arguably) to set up your shared instance like so:
static ShoppingCart *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[self alloc] init];
instance.items = [NSMutableDictionary dictionary];
});
return instance;

Resources