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