1. Welcome to the new MacRumors forums. See our announcement and read our FAQ

Obj-C: instance variables from another object

Discussion in 'Mac Programming' started by Byzanti, May 14, 2012.

  1. Byzanti, May 14, 2012
    Last edited: May 14, 2012

    macrumors newbie


    If I call an instance variable (set with @property) from another object, does that entire variable get reloaded into memory?

    For example, I allocate an object at the start of my code, and part of the initialisation loads a large NSDictionary into memory.
    EXSomeObject *someObject = [[EXSomeObject alloc] init];

    If I later try and access a key from this dictionary from outside EXSomeObject itself, does the whole dictionary get reloaded elsewhere?

    Eg NSLog(@"%@",[[someObject someDictionary] objectForKey:mad:"someKey"]);

    Even if it doesn't, it this considered bad practice for some reason or other?

    Many thanks!
  2. macrumors 68040


    You haven't really explained how your dictionary gets from one place to another. If you're just copying the pointer, the object is not getting copied. If you assign to a property that uses "copy" than the object will get copied and use more memory. If you manually copy, same issue. If you're pointing to the same memory from multiple pointers, no problem.

    If you show more actual code we can tell you specifically what's happening.

  3. macrumors 6502a

    If I understand your question correctly then no, it doesn't - someObject points to a dictionary, and if you pass the value of someObject elsewhere then it will still point to the same dictionary. Unless you say

    EXSomeObject *newobject = [someObject copy]
    which produces a copy of the object someObject points to then you'll be working with the same EXSomeObject.

    Take some time to read up on the difference between objects and pointers to objects, that's what this is about.
  4. macrumors newbie

    Thanks to both of you for your help! knightlie, the second part was exactly what I was wondering about.
  5. macrumors 68000


    Except, not always. The default -copyWithZone: method does allocate a new, retained object, but some classes, like NSDictionary, NSArray and NSString use copy to merely increment the retain count and return the same pointer, because these objects are immutable so physically copying them would be a waste of time. This, of course, does not apply to their mutable subclasses.
  6. macrumors newbie

    I've read up (again!) on pointers, and what has been said above, but there is evidentially something I don't get.

    In the following code, when I build and analyse it informs me that there is a 'potential leak of an object allocated on line X'. However, from reading the above, and from what I have read, I should not be reallocating an object, I should be merely pointing to it?

    The code (simplified):

    @interface MyWindowController : NSWindowController {
         MySomeObject *someObject;
    -(id) init {
         if (self = [super init]) {
               someObject = [[MySomeObject alloc] init];
               //this persists until dealloc
        return self;
    -(void)someMethod {
         //The memory leak is supposedly in the line below
         if ([[someObject someArray] count] == 0) do something;
         else if ([[someObject someArray] count] > 0) do something else;
    @interface CRBrains : NSObject {
         NSArray *someArray;
    @property (copy) NSArray *someArray;
    -(void)setupSomeArray:(NSArray *)twoArrays;
    @synthesize someArray;
    //This array comes from a NSOperation
    -(void)setupSomeArray:(NSArray *)twoArrays {
    	[self setSomeArray:[twoArrays objectAtIndex:0]];
            //There's another array set too, but nm. Both internal arrays and the 'twoArrays' array itself are initialised with class methods, so autoreleased.
    So, to reiterate, my understanding is that in (void)someMethod the [someObject someArray] isn't being assigned, it's just being pointed to. Why should the build and analyse tool flag this up as a potential leak of the object?

    Many thanks
  7. macrumors 68040


    It says it's leaking because it leaks. You said someArray should create a copy on access. You make a copy, you pass count to it, and you let the pointer drift into the ether. You can never release the object you have ownership of. Leak time. No more copy, then retain if you need the returned value around.

  8. macrumors 6502a

    Yes, change the (copy) to (retain) (or even readonly if you will never change the array from outside the object). Also, you should probably say:

    -(void)someMethod {
         int arrayCount = [someObject.someArray count];
         if (arrayCount == 0) do something;
         else if (arrayCount > 0) do something else;
    for two reasons:

    1. It's a tiny bit more efficient to only call the count method once, and bad form to call it twice in succession like that. Why call it twicen when you know the result won't have changed?
    2. Saying someObject.someArray to access a property lets the runtime fetch the property a little more efficiently than [someObject someArray]
  9. macrumors 603

    This is false. The first form is transformed by the compiler into exactly the same result (a method call, message send) as the second form. There is no difference at all.


    myInstance.value = 10;
    printf("myInstance value: %d", myInstance.value);
    When used with objects, however, dot syntax acts as “syntactic sugar”—it is transformed by the compiler into an invocation of an accessor method. Dot syntax does not directly get or set an instance variable. The code example above is exactly equivalent to the following:
    [myInstance setValue:10];
    printf("myInstance value: %d", [myInstance value]);
    (underline added for emphasis)
  10. macrumors 68000


    Or you could just write a specific method for what you need
    - (NSInteger)someArraysCount { return [someArray count]; }
    if you really need to use the copy attribute.
  11. macrumors newbie

    Thank you very much for the help so far, everyone. I've read a lot about pointers, copying, retaining and memory management, and things are much clearer now. I also do have the code working with great with (retain), as has been mentioned. If someone could help my clear up one last piece of confusion, I would be very grateful.

    My problem is with pointers and @property (copy). My understanding is that if I continue to have my someArray set and got by @property (copy) it should be returning me a copy of the current someArray with a retain count of 1.

    In my method above I now have:
    -(void)someMethod {
          NSArray *myArray = [someObject someArray];
          //some other stuff that uses myArray
    Now, this works, except it is still flagged down as a memory leak. I presume this is because @property (copy) is not returning an autoreleased object.

    So, to fix it, I tried these two options:

    -(void)someMethod {
          NSArray *myArray = [[someObject someArray] autorelease];
          //some other stuff that uses myArray
    -(void)someMethod {
          NSArray *myArray = [someObject someArray];
          //some other stuff that uses myArray
          [myArray release];
    The thing is, I actually call this method a few times. In between each call, someObject sets someArray to a new array (using [self someArray:[someautoreleased array]]).

    Both of the methods above work the first time I run them, however they crash the app the second time I run them. I understand that app crashes are because the app is trying to access some memory which has already been released. What I don't understand is why it should be trying to access already released memory.

    Surely by placing NSArray *myArray = [someObject someArray]; at the start of the method, I am getting the latest copy of someArray each time? It should no longer be pointing to the old copy? Indeed, the old copy should no longer exist (having been released), nor be called? But, as the app crashes, I assume I'm either not getting the new copy of someArray, or that myArray is still pointing to the old someArray for some other reason?

  12. macrumors newbie

    Actually, I take back that I had it working when using (retain) rather than (copy).

    In both cases theses lines comes up as a potential object leak:
    NSArray *myArray = [someObject someArray];
    NSArray *myArray = [NSArray arrayWithArray:[someObject someArray]];

    Similarly this line crashes it the second time it's run:
    NSArray *myArray = [[someObject someArray] autorelease];
    (or with [myArray release], or indeed [myArray autorelease]).

    I don't understand this. How do I get it to not leak and not crash?
  13. macrumors 68040


    You're not showing us all your code so we can't identify all of your problems. Start by showing all your code and telling us exactly what happens when you run it.

    You said you read about memory management, which is good, but it still seems like you're hit or miss on ownership. Don't release something you don't own. Don't take ownership of something you don't plan to relinquish ownership of with a release or autorelease.

    A lot of people struggle with this, so stick with it. Break things down to the smallest amount that demonstrates your problem that we can run, and post it.

  14. macrumors 68000


    If you are not worried about thread safety, the (copy) attribute is rarely needed. Personally, I would set the attribute to (retain) and let the caller handle copying. That way you know how the caller will be affecting the lifespan of an object. For instance, if the array is set to (retain) and you are certain another thread will not modify it while you are using it,
    - (void)someMethod {
         NSArray *myArray = [[someObject someArray] [COLOR="Blue"]retain[/COLOR]]; // make sure the array will be alive as long as we need it
         /* use myArray as needed */
         [myArray release]; // release as soon as myArray is no longer needed
         /* maybe do some other stuff*/
    If thread safety is a serious concern (which you have not mentioned), that someArray might change while you are working on it, just replace the "retain" with "copy".
  15. Byzanti, May 18, 2012
    Last edited: Apr 1, 2013

    macrumors newbie

    Lee, you're quite right. I've spent hours and hours on this and I still can't figure it out. Code below. Either the code works right and I leak the object, or I don't leak the object, but it crashes the second time I run the methods.

    Sydde, thank you for your explanation. Can be sure the error isn't in that bit now.

    So, here is my actual code (or the relevant bits - I'll upload the whole damn thing if the error's not in here).

    There are three main classes used in this. The first is a WindowController CRMainWindows, the second is a model CRBrains where I store all the arrays and dictionaries. The third is CRArticleParser which is an NSOperation, and updates the stuff held in CRBrains.

    So, in order, this happens:

    [code removed]

    If I have the autorelease above (or a plain [release]) I don't get a leak error, but I get an EXC_BAD_ACCESS the second time I run it.

    If I don't have the autorelease (or any other) above, then the app runs fine, but I'm told I'm leaking memory.

    Many thanks!
  16. macrumors 6502a

    I haven't run the project yet but I think you need to replace all your (copy) properties with (retain) ones, as Sydde says. It looks to me as if you're ending up with many copies of objects where you want to be dealing with the same one. Is there any reason you're using copy so much?
  17. macrumors newbie

    I've tried all of them on copy, all of them retain, and then mixtures of the two based what I've read. It doesn't seem to make any difference to the problem I'm getting here.

    But, the rules I am following are:
    * If it's an immutable object with a mutable subclass, it's copy.
    * Other objects are retain (or assign for primitives)
    * (Not sure about the logic of this one): NSOperations run on a different thread, so if being initially set from the main thread, I copy them.

    I've read that (copy) only copies if it needs to, otherwise it retains. Also following this: http://jakeboxer.com/blog/2011/10/03/my-pre-arc-objective-c-memory-management-conventions/

Share This Page