How to save data to NSMutableDictionary and load data from NSMutableDictionary - ios

I am trying to create shopping cart. I want to put all data NSMutableDictionary from NSDictionary with Bar-code number which has DataItem variable as key. I have created NSMutableDictionary with that code block;
- (void)viewDidLoad {
[super viewDidLoad];
DataItem = [[[_response objectForKey:#"Data"] objectForKey:#"Items"] objectForKey:#"Item"];
NSMutableDictionary *CartItems = [[NSMutableDictionary alloc]init];
for(NSDictionary *transaction in DataItem)
{
[CartItems setValue:transaction forKey:[transaction objectForKey:#"BarcodeNumber"]];
}
}
When I push another viewController for selection another item to put cart. Once again,push that viewController, it deletes before item from CartItems variable.
I know I have putted that code block NSMutableDictionary *CartItems = [[NSMutableDictionary alloc]init]; inside of viewDidLoad. That's why, It generates new CartItems variable. If I want to put it .h file, it returns nil. I did not find any solution.
Is there any way to load data to NSMutableDictionary for reusing? or Is there another way to create same logic? Thanks.

use a singleton class to store you data like this tutorial

Make a singleton class for data which returns same object with first time initialization and use that for storing your data.
+ (id)getBE {
static MyBEClass *objMyBEClass = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
objMyBEClass = [[self alloc] init];
});
return objMyBEClass;
}
Make CarItems dictionary a property of BE class so you can get this from your view controller.
#property(strong)NSMutableDictionary *CartItems;
In init method of BE class initialize your array/dictionary.
CartItems = [[NSMutableDictionary alloc]init];

You can manage this by using NSUserDefaults. Here is viewDidLoad-
- (void)viewDidLoad {
DataItem = [[[_response objectForKey:#"Data"] objectForKey:#"Items"] objectForKey:#"Item"];
NSUserDefaults *prefrence=[[NSUserDefaults alloc]init];
if ([[NSUserDefaults standardUserDefaults]objectForKey:#"cartItems"]!=nil) {
NSMutableDictionary *CartItems=[[NSUserDefaults standardUserDefaults]objectForKey:#"cartItems"];
for(NSDictionary *transaction in DataItem)
{
[CartItems setValue:transaction forKey:[transaction objectForKey:#"BarcodeNumber"]];
}
[prefrence setObject:CartItems forKey:#"cartItems"];
}else{
NSMutableDictionary *CartItems = [[NSMutableDictionary alloc]init];
for(NSDictionary *transaction in DataItem)
{
[CartItems setValue:transaction forKey:[transaction objectForKey:#"BarcodeNumber"]];
}
[prefrence setObject:CartItems forKey:#"cartItems"];
}
}
whenever you want to clear your cart that time also clear NSUserDefaults using [[NSUserDefaults standardUserDefaults]removeObjectForKey:#"cartItems"].

I would not suggest to use a Singleton for such a thing except if your building a huge app with many controllers, and you need your chart everywhere.
If it's not the case, I would suggest you to pass the char as parameter from one controller to the other one, and pass it back with a delegate as in this guide.
if you have an application built with a single navigation controller, remember that it is not deallocated, so you can save data there. Just make getters and setters of your variable visible (.h file) or the variable itself, but remember that that is not a very good practise because it looks like it will be modified by many controllers, and thats another reason why you should avoid using singletons.
Hope it helps!

Related

Objective C - How To Keep Reference To Multiple Objects With Keys Just Like How NSMutableDictionary Works

I just learned how to make use of KVO, but only the basics. What I need to achieve is something like this:
I have a delegate call that passes a Speaker object.
- (void)onSpeakerFound:(Speaker *)speaker
Once I receive this Speaker in the UI part, from there I will assign observers for this object.
But, this is just for one speaker. What if I have multiple speakers to keep track of. I need to assign observers separately for those speakers and then at the same time I wish to keep their references for further updates to the values.
Each speaker could be updated from time to time. So when I notice that there is a change that happened on a speaker, I wish to access the reference to that speaker and update the values just like how NSMutableDictionary works.
NSMutableDictionary makes a copy of an object set to it so it will be a difference object if I get it again from the dictionary.
So, is there a class that allows me to keep track of an object by just keeping a reference only to that object without making a copy of it?
EDIT: A Test Made To Verify That When An Instantiated Object is Set in an NSMutableDictionary, The Instantiated Object is not referenced with the one set inside NSMutableDictionary.
- (void)viewDidLoad
{
[super viewDidLoad];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
NSString *obj = #"initial value";
NSString *key = #"key";
[dict setObject:obj forKey:key];
NSLog(#"Object is now %#", [dict objectForKey:key]);
obj = #"changed value";
NSLog(#"Object is now %#", [dict objectForKey:key]);
}
Log:
2016-07-26 21:04:58.759 AutoLayoutTest[49723:2144268] Object is now initial value
2016-07-26 21:04:58.761 AutoLayoutTest[49723:2144268] Object is now initial value
NSMutableDictionary makes a copy of an object set to it...
That is not correct; it will add a reference to the object. It will be the same object referenced inside and outside the Objective-C collection.
So, is there a class that allows me to keep track of an object...?
Probably NSMutableSet if you just want a list of the objects. That will take care that you have a unique reference to each object, however you need to implement the methods hash and isEqual on those objects so they behave correctly. Otherwise NSMutableDictionary if you want fast look-up by key.
-try this one
- (void)viewDidLoad
{
[super viewDidLoad];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
NSString *obj = #"initial value";
NSString *key = #"key";
[dict setObject:obj forKey:key];
NSLog(#"Object is now %#", [dict objectForKey:key]);
obj = #"changed value";
[dict setObject:obj forKey:Key];
NSLog(#"Object is now %#", [dict objectForKey:key]);
}

NSMutableArray initializing from viewDidLoad

arrayOfElements = [NSMutableArray arrayWithArray:[someObj getArray]];
and
arrayOfElements = [[NSMutableArray alloc] init];
arrayOfElements = [someObj getArray];
What's the difference?
The first arrayOfElements does not seem to lose its objects when it returns count in numberOfRowsInSection:(NSInteger)section, but the second one does. I get EXC_BAD_ACCESS when I do it the second way.
EDIT:
Can I suppose now that this is the best way,
arrayOfElements = [[NSMutableArray alloc] initWithArray:[someObj getArray]];
because I am initializing an array with the contents of whatever will be autorelease'd, and I now have a fully independent array in the current class, that is viewDidLoad, oops sorry, ViewController.
This line creates an NSMutableArray from an existing array
arrayOfElements = [NSMutableArray arrayWithArray:[someObj getArray]];
This combination first creates an NSMutableArray and then instantly discards it replacing it with what is returned by [someObj getArray]
arrayOfElements = [[NSMutableArray alloc] init]; // Create new NSMutableArray
arrayOfElements = [someObj getArray]; // Throw away the newly created array and replace with the result of [someObj getArray]
If you are not using ARC then it is purely by luck that either would work.
In both cases arrayOfElements is being assigned an autorelease'd object - which will be cleared soon (most likely the next runloop). It is only by chance that nothing else has been written over this point of memory which allows one of your implementations to still work.
If you are not using ARC then really you should update your project to be using it will handle a lot of cases like this for you.
You should definitely be using properties (not bare ivars) as this will help reduce memory issues (for non-ARC) and give a more consistent interface to your code.
In your header (or class extension) declare the property like this
#property (nonatomic, strong) NSMutableArray *arrayOfElements;
Now for ARC you can simple do
[self setArrayOfElements:[[someObj getArray] mutableCopy];
for non-ARC you can do
NSMutableArray *array = [[someObj getArray] mutableCopy];
[self setArrayOfElements:array];
[array release]; array = nil;
Also note that getArray is a bad method name.
The use of “get” is unnecessary, unless one or more values are returned indirectly.
Coding Guidelines
When you are adding objects to mutable array from another array, try this:
[arrayOfElements addObjectsFromArray: [someObj getArray]];
If you're not using ARC, you need to make sure its retained.
if (arrayOfElements) {
[arrayOfElements release];
}
arrayOfElements = [[NSMutableArray alloc] initWithArray:[someObj getArray]];

Copy C pointers to NSMutableDictionary

I have a class that parses through an XML file in iOS.
You can get the data of an element in the form of an TBXMLElement*.
I want to iterate through the XML and make deep copies of the TBXMLElements and store them in an NSMutableDictionary class variable.
How can I:
myClassDict addObject:(TBXMLElement*)element?
You can put the pointers in an NSValue. What key are you going to use?
// Save the TBXMLElement*
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setValue:[NSValue valueWithPointer:element] forKey:#"whatKey"];
…
// Get the TBXMLElement*
TBXMLElement *el = (TBXMLElement *)[[dict valueForKey:#"whatKey"] pointerValue];
Like said in the comments, you will have to wrap TBXMLElement* in a subclass of NSObject. Probably something like:
#interface MyXMLElement {
TBXMLElement* _xmlElement;
}
-(void)setXMElement:(TBXMLelement*)element;
#end
You can then populate the element:
MyXMLElement *elmt = [[MyXMLElement alloc] init];
[emlt setXMLElement:pointerToTBXMLElement];
[someArray addObject:elmt];

What is the best way to save permanent data in one class and be able retrieve it in another class

I would like to save this array of dictionaries and be able to retrieve it another class and make decisions based upon it.
this is the array:
NSArray* cellInfoArray = [[NSArray alloc] initWithObjects:[manufacturerTextField text],[lotNumberTextField text],[expirationDateTextField text],[techniqueTextField text],[cellNumberTextField text],[rhhrProfileTextField text],[donorNumberTextField text], nil];
NSArray* keyNamingArray = [[NSArray alloc] initWithObjects:#"company",#"lot",#"expDate",#"tech",#"whichCell",#"rhTyping",#"donor", nil];
NSArray* resultsArray = [[NSArray alloc] initWithObjects:[capitalDResultLabel text],[capitalCResultLabel text],[capitalEResultLabel text],[cResultLabel text],[eResultLabel text],[fStarResultLabel text],[cwResultLabel text],[vResultLabel text],[capitalKResultLabel text],[kResultLabel text],[kpaResultLabel text],[kpbResultLabel text],[jsaResultLabel text],[jsbResultLabel text],[fyaResultLabel text],[fybResultLabel text],[jkaResultLabel text],[jkbResultLabel text],[xgaResultLabel text],[leaResultLabel text],[lebResultLabel text],[capitalSResultLabel text],[sResultLabel text],[mResultLabel text],[nResultLabel text],[p1ResultLabel text],[luaResultLabel text],[lubResultLabel text], nil];
NSArray* antigenNames = [[NSArray alloc] initWithObjects:#"D",#"C",#"E",#"c",#"e",#"f*",#"Cw",#"V",#"K",#"k",#"Kpa",#"Kpb",#"Jsa",#"Jsb",#"Fya",#"Fyb",#"Jka",#"Jkb",#"Xga",#"Lea",#"Leb",#"S",#"s",#"M",#"N",#"P1",#"Lua",#"Lub", nil];
_cellInfo = [[NSMutableDictionary alloc] initWithObjects:cellInfoArray forKeys:keyNamingArray];
_resultDictionary = [[NSMutableDictionary alloc] initWithObjects:resultsArray forKeys:antigenNames];
finalCellOne = [[NSMutableDictionary alloc] initWithObjectsAndKeys:_cellInfo,#"clerk",_resultDictionary,#"theResults", nil];
this is probably something basic, but i have been trying several things (archiver, property list, nsuserdefaults) and i keep getting "null".
the user should be able to modify the data; thus, if we use a filepath, the second class should know that too.
i dont necessarily need any code from you guys; if i get some guidance on where to focus my research to be able to do this, it would be appreciated.
Thanks guys
It sounds like a case where a singleton class would be of use to you. Application-wide access to the data and serialization/deserialization would be handled by your singleton.
#interface ApplicationData : NSObject
+ (id)sharedData;
// your class properties that expose the data
#end
#implementation ApplicationData
+ (id)sharedData {
static dispatch_once_t pred;
static ApplicationData *cSharedInstance = nil;
dispatch_once(&pred, ^{ cSharedInstance = [[self alloc] init]; });
return cSharedInstance;
}
// you'll need to provide for serialization/deserialization as you are doing now.
#end
Thereafter, your access to the shared data is via: [[ApplicationData sharedData] cellInfoArray] etc.

Persistance storage for UIVIew

I am creating dynamically some "n" number of UIView Object in my application.I can able to drag, drop these objects to any position in the screen & chenge change their some of property .Now i want to save all these details with persistance storage ,so that whenever i launched the application nest time, i can able to see those already created object.
So what is the best solution for this?
Also is their any sample application available for this form which i can take reference?
I think you can do it this way.
// Create an array to store the properties
NSMutableArray *viewProperties = [NSMutableArray array];
// Loop through all the views
for (UIView *view in views) {
// Create a dictionary for each view
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
// Store the properties in the dictionary
[dict setValue:NSStringFromCGRect(view.frame) forKey:#"ViewFrame"];
...
// Add the dictionary to the array
[viewProperties addObject:dict];
}
// Finally add the array to persistence
[userDefaults setValue:viewProperties forKey:#"ViewProperties"];
Later you can get the array from persistence and create the views with the properties.
NSMutableArray *viewProperties = [userDefaults valueForKey:#"ViewProperties"];
for (NSDictionary *dict in viewProperties) {
UIView *view = [[UIView alloc] init];
NSString *frameAsString = [dict valueForKey:#"ViewFrame"];
view.frame = CGRectFromString(frameAsString);
// Get other properties from dictionary and set it to view
}

Resources