Amazon.com Widgets Program listing for 19.7 - not required to release mybook?
Welcome, Guest. Please login or register.
Did you miss your activation email?
September 21, 2014, 09:11:37 PM
Home Help Search chat Login Register 
News: Read this please.The Great Kangaroo Escape Looking for reviews of the 4th ed on Amazon!   Twitter:  @skochan
                     

+ Official Forum for Programming in Objective-C (the iPhone Programming Language) - Stephen Kochan
|-+ Old Stuff
| |-+ Chapter Study
| | |-+ Chapter 19 - Archiving
| | | |-+ Program listing for 19.7 - not required to release mybook?
Pages: [1] Go Down
Print
Author Topic: Program listing for 19.7 - not required to release mybook? (Read 2688 times)
Jyrbian
Newbie
*
Posts: 22






on: February 20, 2010, 12:36:17 AM

In this program listing mybook is not getting released.

I confirmed that attempting to release will cause and Exec Bad Access error.

This does make it easy for memory management, but I would like to better understand why, especially since there are retain messages in the initWithCoder method.

Did I miss something in the book?

Thanks,
Mark
Logged
esc
Global Moderator
Full Member
*****
Posts: 230






Reply #1 on: February 20, 2010, 12:28:04 PM

unarchiveObjectWithFile: is a class method.  You're not the owner of the object returned by it, so you don't need to release it.

It triggers -initWithCoder: and since bookName and book are objects returned by decodeObjectForKey: and those objects (which are not owned by you) you wish to access beyond the scope of the method initWithCoder:, so you need to retain them.

When you release the AddressBook instance variables or set them to nil (in dealloc), then your retain/release count would be matched.

Hope this helps :-)
Logged
skochan
Administrator
Hero Member
*****
Posts: 3114







Reply #2 on: February 20, 2010, 01:22:36 PM

Like Wendy said, the objects that the unarchiver creates in the decoding process get released when the unarchiving is done.   So you need to retain your objects so they don't get destroyed.

Cheers,

Steve Kochan
Logged
Jyrbian
Newbie
*
Posts: 22






Reply #3 on: February 20, 2010, 05:25:39 PM

That clears it up.

I am trying to make sure I am managing memory correctly.

Thank you.
Mark
Logged
skochan
Administrator
Hero Member
*****
Posts: 3114







Reply #4 on: February 22, 2010, 01:07:17 PM

I am trying to make sure I am managing memory correctly.

It was a great question, and I'll be sure to make that clearer in the next edition of my book.

Cheers,

Steve Kochan
Logged
sinth
Newbie
*
Posts: 35






Reply #5 on: May 27, 2010, 01:40:57 AM

Hope you don't mind for digging this old thread up, it fitted perfectly for this question =)

The program's in this chapter have been confusing, first of the retain message in the initWithCoder methods should be explained =) I had no clue that all the unarchived objects we're destroyed when the unarchive method ended.

The second thing i didn't understand was this:

Main 1
Code: (Objective-C)
/* Uses class from program 19.8 */
//With this method added to it
-(void)retainCountPost
{
NSLog(@"STRVAL: %x SELF: %x",[strVal retainCount],[self retainCount]);
}



#import <Foundation/Foundation.h>
int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

Foo *myFoo1 = [[Foo alloc] init];
Foo *myFoo2;

[myFoo1 setStrVal:@"This is the string"];
[myFoo1 setIntVal:12345];
[myFoo1 setFloatVal:98.6];

[NSKeyedArchiver archiveRootObject:myFoo1 toFile:@"foo.arch"];

myFoo2 = [NSKeyedUnarchiver unarchiveObjectWithFile:@"foo.arch"];
NSLog(@"%@\n%i\n%g",[myFoo2 strVal],[myFoo2 intVal],[myFoo2 floatVal]);

[myFoo2 retainCountPost];
    [pool drain];
[myFoo2 retainCountPost];
return 0;
}

The myFoo2 object is not released when the pool is drained. It seems that i have to add a dealloc method for the Foo class that releases the strVal , if i do that the Foo object will be released aswell.
I find this very confusing becuse of the fact that dealloc is called when retainCount reaches zero from a release method?

Adding this method to the Class
Code: (Objective-C)
-(void)dealloc
{
[strVal release];
[super dealloc];
}

Main 2
Code: (Objective-C)
int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

Foo *myFoo1 = [[Foo alloc] init];
Foo *myFoo2;

[myFoo1 setStrVal:@"This is the string"];
[myFoo1 setIntVal:12345];
[myFoo1 setFloatVal:98.6];

[NSKeyedArchiver archiveRootObject:myFoo1 toFile:@"foo.arch"];

myFoo2 = [NSKeyedUnarchiver unarchiveObjectWithFile:@"foo.arch"];
NSLog(@"%@\n%i\n%g",[myFoo2 strVal],[myFoo2 intVal],[myFoo2 floatVal]);

[myFoo2 retainCountPost];
    [pool drain];

//removed , causes EXC_BAD_ACCESS
//[myFoo2 retainCountPost];
return 0;
}

And one last note, if i add this code and remove the dealloc method:
Code: (Objective-C)
        [pool drain];
[myFoo2 retainCountPost];
[[myFoo2 strVal] release];
[myFoo2 retainCountPost];

Suggests that myFoo2 IS held alive as long as some member of the object has a reference count. And when that member is released so is the object.
Logged
skochan
Administrator
Hero Member
*****
Posts: 3114







Reply #6 on: May 27, 2010, 10:14:29 AM

Your question brought up a good point (not directly related to your question):  if you unarchive an instance variable that was autoreleased before it was archived, then you should autorelease it when it is unarchived.   That way it gets cleaned up in a consistent manner.  You want to release objects in dealloc that you retained or created with copy, alloc, or new, but not those that were autoreleased.  

So in order for your memory management strategy to be consistent and to work correctly for archived and unarchived objects, you need to make sure that you maintain the autorelease nature of each object.  

Getting back to the example (which really doesn't deal with autoreleased objects), I see now that there should be a dealloc method defined in the class to release str1 since the property was defined with a copy attribute.

And myFoo2 should be released before the program terminates.

Cheers,

Steve

Last Edit: May 27, 2010, 10:16:53 AM by skochan Logged
sinth
Newbie
*
Posts: 35






Reply #7 on: May 27, 2010, 12:05:39 PM

Hmm, i tried to figure out what you meant with the first paragraph, only when i pressed reply i saw "(not directly related to your question)", that sentence doesn't show on the forum for me :/ Thanks for pointing that out.

You mean myFoo1 should be released with a release call, yeah i forgot it =)
However myFoo2 is autoreleased so it should be drained with the pool.

I got two more question, correct me if i am wrong here but wouldn't:

Code: (Objective-C)
strVal = [[decoder decodeObjectForKey:@"FoostrVal"] retain];

Make the program leak? It's better to set it to autorelease. Since the setter for strVal just makes a copy of the object we don't have a reference to it for later release? I tested this with a code (attachment) and the retainCount is 1 on the that object returned after unarchiver method in main.

The thing i really don't get about the unarchiver is that, when the unarchiveObjectWithFile: is called it will trigger the initWithCoder: methods.

In that scope why must i retain the value returned by decodeObjectForKey: , this value is used immediately to set the strVal (and documentation says that the value returned by decodeObjectForKey: is autoreleased). So why do i need to retain it, i use it in the same scope?

Time for some coffee now, i hope i'm not to naggy Steve, hopefully you get something out of this as well =)
Logged
skochan
Administrator
Hero Member
*****
Posts: 3114







Reply #8 on: May 27, 2010, 12:27:41 PM

I need to back up here and see if I can summarize this with a set of rules (I realized that some of the comments in my previous post are inaccurate):

1. All objects returned by the decodObjectForKey: method are autoreleased.
2. You need to retain any decoded object if you want it to survive the release of the autorelease pool.   This is not an issue for the examples in Chapter 19, but is an issue for iPhone applications, in which a new autorelease pool is created and drained for each event cycle.
3. If you retain an object in the decoder, you should override dealloc to release it.
4. If you have the retain property attribute for an instance variable, you can use the setter for the instance variable and let it retain the object for you.   It would still need to be released in dealloc.

Cheers,

Steve
Logged
sinth
Newbie
*
Posts: 35






Reply #9 on: May 27, 2010, 01:43:40 PM

I assumed the strVal = assignment had the function of self.strVal = assignment. I got the logic now, thanks for keeping up =) Jesus, i should have figured this out sooner...

self.strVal = the setter method used , this one copies the value (no need for retain on decodeObjectForKey since the value is copied, it can be autoreleased cuse we don't need it anymore, dealloc is needed to free the strVal)
strVal = normal assignment (that's why the retain is done on the decodeObjectForKey, and dealloc is used to release it)

Logged
skochan
Administrator
Hero Member
*****
Posts: 3114







Reply #10 on: May 27, 2010, 06:27:17 PM

This is complicated stuff.  I often have to rethink the logic myself.  I admire your perseverance in wanting to figure this all out.

Cheers,

Steve
Logged
Pages: [1] Go Up
Print
Jump to:



Login with username, password and session length

Powered by MySQL Powered by PHP Powered by SMF 1.1.11 | SMF © 2006-2009, Simple Machines LLC Valid XHTML 1.0! Valid CSS!
Entire forum contents (c) 2009 classroomM.com. All rights reserved.