NSDictionary dictionaryWithContentsOfFile in Carbon app

  • Hi,

    I have a Carbon application and I have just added my first Cocoa
    stuff and have a couple of questions relating to have memory is
    deallocated.
    Everything seems to work fine but I'm curious if I'm doing things
    correctly (I'm a newbie with Obj-C and Cocoa).

    Basically I use

    NSDictionary *aDictionary = [NSDictionary
    dictionaryWithContentsOfFile:[aString stringByExpandingTildeInPath]];

    NSArray *anArray =  [aDictionary objectForKey: @"aKey"];

    and they are called from a member function in a C++ class

    Here is what I do:

    class foo
    {
    public:
    foo();
    ~ foo();

    void bar(); // this function will be called several times

    private:
    NSDictionary * aDictionary;
    NSArray * anArray;
    NSAutoreleasePool *pool;

    };

    foo:: foo()
    {

    aDictionary = 0;
    anArray = 0;

    pool = [[NSAutoreleasePool alloc] init];

    }

    CItunesImportDialog::~CItunesImportDialog()
    {
    [ aDictionary release];
    [ anArray release];

    [pool release];
    }

    // this function will be called several times
    void foo::bar()
    {

    .....

    [aDictionary release]; // ???

    aDictionary = [NSDictionary dictionaryWithContentsOfFile:[aString
    stringByExpandingTildeInPath]];

    [aDictionary retain]; // ???

    [anArray release]; // ???

    anArray =  [aDictionary objectForKey: @"aKey"];

    [anArray retain]; // ???

    ......

    //now use the array

    }

    So my question is:
    Will the memory that is allocated by the aDictionary and anArray be
    released when my  destructor call [pool release];
    if not, when does this happen?

    also, is my use of retain and release correct - without it crashes so
    it seems so?

    Thanks for any comments/explanations

    Rolf
  • Am 08.10.2006 um 09:52 schrieb Roni Music:
    > I have a Carbon application and I have just added my first Cocoa
    > stuff and have a couple of questions relating to have memory is
    > deallocated.
    > Everything seems to work fine but I'm curious if I'm doing things
    > correctly (I'm a newbie with Obj-C and Cocoa).

    In short, you're doing it wrong. Autorelease pools are not like
    Apache API memory pools. They're not intended to be kept around in
    instance vars (they stack, so you really should only create one at
    the start of a function and release it at the end).

    Just create the pool at the start of any function that calls into
    Cocoa and release it before exiting the function. May be a good idea
    to create an auto_ptr-like object to take ownership of and release
    ObjC objects. Another good idea would be to add ObjC exception
    handlers, too, see NS_DURING and NS_HANDLER and NS_ENDHANDLER or @try
    and @catch -- C++ doesn't understand ObjC exceptions.

    If you want to keep any object that you don't own (see <http://
    devworld.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/Tasks/
    MemoryManagementRules.html> for details on ownership), you must
    retain it before you store it in an ivar and release it once you
    don't need it anymore (e.g. before replacing it with a new object
    when you change its value and in your destructor). If you already own
    it, you can just store it away in an ivar, but you still need to
    release it.

    Cheers,
    -- M. Uli Kusterer
    http://www.zathras.de
  • Hi,

    Thanks for responding!

    ----- Original Message -----
    From: "Uli Kusterer" <witness.of.teachtext...>
    To: "Roni Music" <roni3...>
    Cc: <cocoa-dev...>
    Sent: Sunday, October 08, 2006 12:53 PM
    Subject: Re: NSDictionary dictionaryWithContentsOfFile in Carbon app

    > Am 08.10.2006 um 09:52 schrieb Roni Music:
    >> I have a Carbon application and I have just added my first Cocoa  stuff
    >> and have a couple of questions relating to have memory is  deallocated.
    >> Everything seems to work fine but I'm curious if I'm doing things
    >> correctly (I'm a newbie with Obj-C and Cocoa).
    >
    > In short, you're doing it wrong. Autorelease pools are not like  Apache
    > API memory pools. They're not intended to be kept around in  instance vars
    > (they stack, so you really should only create one at  the start of a
    > function and release it at the end).

    OK

    >
    > Just create the pool at the start of any function that calls into  Cocoa
    > and release it before exiting the function. May be a good idea  to create
    > an auto_ptr-like object to take ownership of and release  ObjC objects.
    > Another good idea would be to add ObjC exception  handlers, too, see
    > NS_DURING and NS_HANDLER and NS_ENDHANDLER or @try  and @catch -- C++
    > doesn't understand ObjC exceptions.
    >
    > If you want to keep any object that you don't own (see <http://
    > devworld.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/Tasks/
    > MemoryManagementRules.html> for details on ownership), you must  retain it
    > before you store it in an ivar and release it once you  don't need it
    > anymore (e.g. before replacing it with a new object  when you change its
    > value and in your destructor). If you already own  it, you can just store
    > it away in an ivar, but you still need to  release it.

    I want to keep the NSDictionary and NSArray objects as long as my C++ class
    exists,
    since other member functions also uses it.

    Would this modified example be correct?

    class foo
    {
    public:
    foo();
    ~ foo();

    void bar(); // this function will be called several times

    void ThisFunctionWillUseTheNSArray(); // this function will be called
    several times

    private:
    NSDictionary * m_aDictionary;
    NSArray * m_anArray;

    // private helper class to handle the NSAutoRelease stuff
    class CAutoRelease
    {
    public:
      CAutoRelease()
      {
      m_pool = [[NSAutoreleasePool alloc] init];
      }

      ~CAutoRelease()
      {
      [m_pool release];
      }

    private:
      NSAutoreleasePool *m_pool;

    };

    };

    //////////////////////

    foo:: foo()
    {
    m_aDictionary = 0;
    m_anArray = 0;
    }

    foo::~foo()
    {
    [ m_aDictionary release];
    [ m_anArray release];
    }

    // this function will be called several times
    // uses the dictonary and array objects
    void ThisFunctionWillUseTheNSArray()
    {
    CAutoRelease autoReleaseMe;

    /*
    uses m_aDictionary and m_anArray
    */

    }

    // this function will be called several times
    // creates the dictonary and array objects
    void foo::bar()
    {
    CAutoRelease autoReleaseMe;

    .....

    [m_aDictionary release]; // OK to release even if it's NULL? (which it is
    the first time being called)

    aDictionary = [NSDictionary dictionaryWithContentsOfFile:[aString
    stringByExpandingTildeInPath]];

    [m_aDictionary retain];

    [m_anArray release];

    anArray =  [aDictionary objectForKey: @"aKey"];

    [m_anArray retain];

    ......

    //now use the array

    }

    Rolf
  • Am 08.10.2006 um 20:51 schrieb Roni Music:
    > Would this modified example be correct?

      In principle, yes. But you need to get your variable names right:
    You sometimes wrote anArray and aDictionary where it should be
    m_anArray and m_aDictionary :-p

    > foo:: foo()
    > {
    > m_aDictionary = 0;
    > m_anArray = 0;
    > }

      Just a small style thing: It's a pointer, not an int, so you
    *should* really be assigning this NULL instead of zero to make that
    clear. Also, in ObjC the convention is to use the constant "nil" to
    mean "an uninitialized object" (it's basically the same as NULL, but
    I use the three to help me distinguish in code: 0 is an int, 0.0 a
    float, NULL a classic pointer or C++ object and nil an ObjC object.

    > // this function will be called several times
    > // creates the dictonary and array objects
    > void foo::bar()
    > {
    > CAutoRelease autoReleaseMe;
    >
    > .....
    >
    > [m_aDictionary release]; // OK to release even if it's NULL? (which
    > it is the first time being called)
    >
    > aDictionary = [NSDictionary dictionaryWithContentsOfFile:[aString
    > stringByExpandingTildeInPath]];
    >
    > [m_aDictionary retain];
    >
    >
    >
    > [m_anArray release];
    >
    > anArray =  [aDictionary objectForKey: @"aKey"];
    >
    > [m_anArray retain];
    >
    > ......
    >
    > //now use the array
    >
    > }

    Yes, if you look at Apple's Objective C book <http://
    developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/
    ObjC.pdf> on page 42, you'll see that you can safely send messages to
    NIL as long as the method's return type is one of a select few. Since
    the return type of retain is void, that's OK, too. (Though I'm kinda
    surprised the docs don't mention "void" as being OK, I should
    probably file a bug about that).

    Cheers,
    -- M. Uli Kusterer
    http://www.zathras.de
  • ----- Original Message -----
    From: "Uli Kusterer" <witness.of.teachtext...>
    To: "Roni Music" <roni3...>
    Cc: <cocoa-dev...>
    Sent: Sunday, October 08, 2006 11:12 PM
    Subject: Re: NSDictionary dictionaryWithContentsOfFile in Carbon app

    > Am 08.10.2006 um 20:51 schrieb Roni Music:
    >> Would this modified example be correct?
    >
    > In principle, yes.

    Good!

    > But you need to get your variable names right:  You sometimes wrote
    > anArray and aDictionary where it should be  m_anArray and m_aDictionary
    > :-p

    Yes, this wouldn't compile and actually never tried
    just a dummy example to explain questions,

    >
    >> foo:: foo()
    >> {
    >> m_aDictionary = 0;
    >> m_anArray = 0;
    >> }
    >
    > Just a small style thing: It's a pointer, not an int, so you  *should*
    > really be assigning this NULL instead of zero to make that  clear.

    Comming from the Windows world, I usually use Hungarian notation to make
    clear what kind of type variables are

    int *m_pToSomething = 0;

    but it's of coure allways good to be as clear as possible

    again thanks for responding!

    Rolf

    > Also, in ObjC the convention is to use the constant "nil" to  mean "an
    > uninitialized object" (it's basically the same as NULL, but  I use the
    > three to help me distinguish in code: 0 is an int, 0.0 a  float, NULL a
    > classic pointer or C++ object and nil an ObjC object.

    >
    >> // this function will be called several times
    >> // creates the dictonary and array objects
    >> void foo::bar()
    >> {
    >> CAutoRelease autoReleaseMe;
    >>
    >> .....
    >>
    >> [m_aDictionary release]; // OK to release even if it's NULL? (which  it
    >> is the first time being called)
    >>
    >> aDictionary = [NSDictionary dictionaryWithContentsOfFile:[aString
    >> stringByExpandingTildeInPath]];
    >>
    >> [m_aDictionary retain];
    >>
    >>
    >>
    >> [m_anArray release];
    >>
    >> anArray =  [aDictionary objectForKey: @"aKey"];
    >>
    >> [m_anArray retain];
    >>
    >> ......
    >>
    >> //now use the array
    >>
    >> }
    >
    > Yes, if you look at Apple's Objective C book <http://
    > developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/ ObjC.pdf>
    > on page 42, you'll see that you can safely send messages to  NIL as long
    > as the method's return type is one of a select few. Since  the return type
    > of retain is void, that's OK, too. (Though I'm kinda  surprised the docs
    > don't mention "void" as being OK, I should  probably file a bug about
    > that).
    >
    > Cheers,
    > -- M. Uli Kusterer
    > http://www.zathras.de
    >
    >
    >
previous month october 2006 next month
MTWTFSS
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31          
Go to today