Memory management when to use release - ios

I had another question about memory management in iOS 3.0+, I know if we did [varialbe release] will release its retain to an object, but code like this -
- (void) getPostsFromJson:(NSData *)data
{
NSError *theError = nil;
NSDictionary *dict = [[CJSONDeserializer deserializer] deserializeAsDictionary:data error:&theError];
if (dict == nil) {
[SystemStatusValues getInstance].isValidJson = NO;
[SystemStatusValues getInstance].httpStatus = HTTP_STATUS_FAILED;
NSLog(#"getPostsFromJson - %# %#",
[theError localizedDescription],
[[theError userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
} else {
NSArray *keys = [dict allKeys];
keys = [keys sortedArrayUsingFunction:keySortByInteger context:nil];
self.keys = keys;
self.posts = dict;
NSLog(#"Posts : getPostsFromJson = %#", self.posts);
if ([keys count] < TOTAL_SECTIONS) {
[SystemStatusValues getInstance].isValidJson = NO;
} else {
[SystemStatusValues getInstance].isValidJson = YES;
if (self.nextPosts == nil) {
}
}
// [keys release];
// [dict release];
return;
}
}
You can see there are two local variables - keys and dict, did I need to call [keys release] or [dict release] at the end of code? Actually I did it, but it brings crushing sometimes. So for local variables, we don't need to release it after it's used?

Both dict and keys are reference to autoreleased objects. You shouldn't release them, which will cause your program to terminate. You Don’t Own Objects Returned by Reference and You must not relinquish ownership of an object you do not own
So for local variables, we don't need to release it after it's used? If you own the objects you must release them when you no longer need them, doesn't matter if its local variable or ivar.
Read this - Advanced Memory Management Programming guide

It's simple:
If you alloc, copy or retain an object
you need to release it. Otherwise you don’t.
So you don't need to release either keys or dict (they're both autoreleased).

Don't release keys array. Because allKeys method probably returns autoreleased NSArray object. So it will be released later by system.
It seems like deserializeAsDictionary also returns an autoreleased NSDictionary, so you shouldn't release it too.
Release objects only created with alloc. In this case, you're using external methods. You need to follow that methods, and see if that object are created with alloc.

Related

Issue facing in isKindOfClass in iOS10

Recently I have upgraded XCode8 I am facing issue in isKindOfClass method this code is working till to iOS9 but in iOS10 suddenly [items isKindOfClass: [NSMutableArray class]] compiler not going in for loop condition may I know what is the reason?
NSMutableArray is child class of NSArray so when I am changing to [NSArray class] then it works fine so I am confuse why this change affect to NSMutableArray class which is child class of NSArray ?
NSMutableArray *items = [jsonDictionary objectForKey:#"items"]; // Here i am taking response in NSMutableArray
if ([items isKindOfClass: [NSMutableArray class]] && items != nil) // not working {
for (NSMutableDictionary *item in items)
{
// Rest of Code
}
}
This code works for me I m confuse the above code working until iOS9 when I change this below code then after working in iOS10:
NSMutableArray *items = [jsonDictionary objectForKey:#"items"];
if ([items isKindOfClass: [NSArray class]] && items != nil) // Changed to NSArray {
for (NSMutableDictionary *item in items)
{
// Rest of Code
}
}
From your comments, it seems that you actually have an NSArray, not an NSMutableArray, so isKindOfClass is working correctly. AFN will give immutable containers unless you specify otherwise, and this shouldn't be any different on iOS 10, so I am not sure why it was working previously.
Rather than testing for a mutable array, it is probably simpler to create a mutable copy of whatever is there, this way you don't have to try and handle the "failure" condition gracefully:
NSArray *items = [jsonDictionary objectForKey:#"items"];
if (items != nil) {
NSMutableArray *mutableItems = [items mutableCopy];
for (NSMutableDictionary *item in mutableItems)
{
// Rest of Code
}
}
Beware, unless you have specified the option to AFN to provide mutable containers, the dictionaries inside your items array will be NSDictionary not NSMutableDictionary, so you may need to make mutable copies of them.
Of course, if you aren't mutating the array or the dictionary, then you can just u NSArray and NSDictionary regardless of whether you have a mutable or immutable object.

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

How to tell the difference between a Boolean and an NSNumber in CoreData

I have some parsing code I'm using for serialising and deserialising objects from our web service and I've hit a bit of a problem when serialising booleans.
The serialisation looks like this:
- (NSDictionary *)dictionaryRepresentationWithMapping:(NSDictionary *)mappingDictionary
{
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc]init];
for (id key in[mappingDictionary allKeys])
{
id value = [self valueForKey:key];
if ((value != [NSNull null]) && (![value isKindOfClass:[NSNull class]]) && (value != nil))
{
[dictionary setObject:value forKey:mappingDictionary[key]];
}
}
return [NSDictionary dictionaryWithDictionary:dictionary];
}
The problem is that when I call valueForKey: on my NSManagedObject and then add this to my dictionary I end up with the value being set as if I was calling:
[dictionary setObject:#1 forKey:mappingDictionary[key]];
instead of:
[dictionary setObject:#YES forKey:mappingDictionary[key]];
This means that when I turn this into JSON, in the next stage, I'm sending 1 instead of true to the server.
So what I need is a way of retaining the fact that this is an NSNumber representing a bool as opposed to a number. I've tried asking for the class but I just get back NSNumber. Is there a way I can retain this automatically or failing that, is there a way I can consult the model to see what the attribute type was set to?
Each entity has its metadata stored in NSEntityDescription and NSAttributeDescription. You can access them from NSManagedObject in a following way:
//you can put this inside the for loop
NSAttributeDescription *attributeDescription = self.entity.attributesByName[key];
if(attributeDescription.attributeType == NSBooleanAttributeType) {
//it is a boolean attribute
}
When sending a call to the server, you could do like this:
[dict setValue:[NSNumber numberWithBool:YES] forKey:mappingDictionary[key]]; ;
Or another way, you can model server side to retain its value as Boolean, and at that time, just need to send like this [dict setValue:YES] forKey:mappingDictionary[key]];
Hope it could help

How to get inserted and updated objects from NSPersistentStoreDidImportUbiquitousChangesNotification?

I want to get the inserted and the update objects from NSPersistentStoreDidImportUbiquitousChangesNotification to do some check on them.
Objects can be of two kind of classes: "Alpha" and "Beta". Both classes have the
property (nonatomic, retain) NSString* name
which is the one I should check.
How do I get it?
The following code doesn't work because it says "name" is an unknown selector:
-(void) checkObjects
{
NSDictionary *insertedObjects = [[note userInfo] objectForKey: #"inserted"];
NSDictionary *updatedObjects = [[note userInfo] objectForKey: #"updated"];
for(NSManagedObject *obj in insertedObjects){
if([obj.entity.managedObjectClassName isEqualToString:#"Alpha"]){
Alpha *alpha = (Alpha*) obj;
if (alpha.name isEqualToString:#"xyz"){
//Do some check
}
}else if([obj.entity.managedObjectClassName isEqualToString:#"Beta"]){
Beta *beta = (Beta*) obj;
if (beta.name isEqualToString:#"xyz"){
//Do some check
}
}
}
}
If I change:
Alpha *alpha = (Alpha*) obj;
Beta *beta = (Beta*) obj;
To:
Alpha *alpha = (Alpha*) obj.entity;
Beta *beta = (Beta*) obj.entity;
alpha = Alpha <-- It is the name of the class, not of the object I want!
beta = Beta <--- It is the name of the class, not of the object I want!
When you get NSPersistentStoreDidImportUbiquitousContentChangesNotification, the objects in userInfo are not managed objects, they're managed object IDs. That is, instances of NSManagedObjectID. If you want to look up attributes on the managed object, you need to get the object corresponding to the ID. Something like
NSDictionary *insertedObjectIDs = [[note userInfo] objectForKey:NSInsertedObjectsKey];
for(NSManagedObjectID *objID in insertedObjects) {
NSError *error = nil;
NSManagedObject *obj = [self.managedObjectContext existingObjectWithID:objID error:&error];
....continue...
}
You may need to change that if self doesn't have a managed object context.
Also, on a slight tangent-- it's generally better to use NSInsertedObjectsKey instead of #"inserted" and NSUpdatedObjectsKey instead of #"updated". Apple probably won't change the key names, but they could, so using the key names instead of string literals is a better choice.

Objective-C: Fixing memory management in a method

I'm almost there understanding simple reference counting / memory management in Objective-C, however I'm having a difficult time with the following code. I'm releasing mutableDict (commented in the code below) and it's causing detrimental behavior in my code. If I let the memory leak, it works as expected, but that's clearly not the answer here. ;-) Would any of you more experienced folks be kind enough to point me in the right direction as how I can re-write any of this method to better handle my memory footprint? Mainly with how I'm managing NSMutableDictionary *mutableDict, as that is the big culprit here. I'd like to understand the problem, and not just copy/paste code -- so some comments/feedback is ideal. Thanks all.
- (NSArray *)createArrayWithDictionaries:(NSString *)xmlDocument
withXPath:(NSString *)XPathStr {
NSError *theError = nil;
NSMutableArray *mutableArray = [[[NSMutableArray alloc] init] autorelease];
//NSMutableDictionary *mutableDict = [[NSMutableDictionary alloc] init];
CXMLDocument *theXMLDocument = [[[CXMLDocument alloc] initWithXMLString:xmlDocument options:0 error:&theError] retain];
NSArray *nodes = [theXMLDocument nodesForXPath:XPathStr error:&theError];
int i, j, cnt = [nodes count];
for(i=0; i < cnt; i++) {
CXMLElement *xmlElement = [nodes objectAtIndex:i];
if(nil != xmlElement) {
NSArray *attributes = [NSArray array];
attributes = [xmlElement attributes];
int attrCnt = [attributes count];
NSMutableDictionary *mutableDict = [[NSMutableDictionary alloc] init];
for(j = 0; j < attrCnt; j++) {
if([[[attributes objectAtIndex:j] name] isKindOfClass:[NSString class]])
[mutableDict setValue:[[attributes objectAtIndex:j] stringValue] forKey:[[attributes objectAtIndex:j] name]];
else
continue;
}
if(nil != mutableDict) {
[mutableArray addObject:mutableDict];
}
[mutableDict release]; // This is causing bad things to happen.
}
}
return (NSArray *)mutableArray;
}
Here's an equivalent rewrite of your code:
- (NSArray *)attributeDictionaries:(NSString *)xmlDocument withXPath:(NSString *)XPathStr {
NSError *theError = nil;
NSMutableArray *dictionaries = [NSMutableArray array];
CXMLDocument *theXMLDocument = [[CXMLDocument alloc] initWithXMLString:xmlDocument options:0 error:&theError];
NSArray *nodes = [theXMLDocument nodesForXPath:XPathStr error:&theError];
for (CXMLElement *xmlElement in nodes) {
NSArray *attributes = [xmlElement attributes];
NSMutableDictionary *attributeDictionary = [NSMutableDictionary dictionary];
for (CXMLNode *attribute in attributes) {
[attributeDictionary setObject:[attribute stringValue] forKey:[attribute name]];
}
[dictionaries addObject:attributeDictionary];
}
[theXMLDocument release];
return attributeDictionaries;
}
Notice I only did reference counting on theXMLDocument. That's because the arrays and dictionaries live beyond the scope of this method. The array and dictionary class methods create autoreleased instances of NSArray and NSMutableDictionary objects. If the caller doesn't explicitly retain them, they'll be automatically released on the next go-round of the application's event loop.
I also removed code that was never going to be executed. The CXMLNode name method says it returns a string, so that test will always be true.
If mutableDict is nil, you have bigger problems. It's better that it throws an exception than silently fail, so I did away with that test, too.
I also used the relatively new for enumeration syntax, which does away with your counter variables.
I renamed some variables and the method to be a little bit more Cocoa-ish. Cocoa is different from most languages in that it's generally considered incorrect to use a verb like "create" unless you specifically want to make the caller responsible for releasing whatever object you return.
You didn't do anything with theError. You should either check it and report the error, or else pass in nil if you're not going to check it. There's no sense in making the app build an error object you're not going to use.
I hope this helps get you pointed in the right direction.
Well, releasing mutableDict really shouldn't be causing any problems because the line above it (adding mutableDict to mutableArray) will retain it automatically. While I'm not sure what exactly is going wrong with your code (you didn't specify what "bad things" means), there's a few general things I would suggest:
Don't autorelease mutableArray right away. Let it be a regular alloc/init statement and autorelease it when you return it ("return [mutableArray autorelease];").
theXMLDocument is leaking, be sure to release that before returning. Also, you do not need to retain it like you are. alloc/init does the job by starting the object retain count at 1, retaining it again just ensures it leaks forever. Get rid of the retain and release it before returning and it won't leak.
Just a tip: be sure that you retain the return value of this method when using it elsewhere - the result has been autoreleased as isn't guaranteed to be around when you need it unless you explicitly retain/release it somewhere.
Otherwise, this code should work. If it still doesn't, one other thing I would try is maybe doing [mutableArray addObject:[mutableDict copy]] to ensure that mutableDict causes you no problems when it is released.
In Memory Management Programming Guide under the topic Returning Objects from Methods (scroll down a bit), there are a few simple examples on how to return objects from a method with the correct memory managment.

Resources