Can you help with cocoa (again)

Discussion in 'Mac Programming' started by ATG, Aug 24, 2005.

  1. ATG macrumors regular

    Joined:
    Aug 7, 2005
    #1
    Sorry for asking so many simple questions. i would like to create more than one array. When I create my first array I do this:
    Code:
    NSMutableArray *myArray = [[NSMutableArray alloc] init];
    Now I have a problem, I want to create a second array but don't know how to do it. Creating an array in the same way as before just crashes my app (which is what I expected it to do).

    Please Help. :confused: :eek:
     
  2. Omen88 macrumors regular

    Omen88

    Joined:
    Jan 8, 2002
    Location:
    Flanders (Belgium)
    #2
    This answer could be terribly stupid, but did you give the second array a different name? Like:
    Code:
    NSArray *myOtherArray = [[NSArray alloc] init];
    and don't forget to release it, when you're done with it.
    Code:
    [myArray release];
     
  3. ozubahn macrumors regular

    Joined:
    Feb 15, 2003
    Location:
    Connecticut
    #3
    To make a second array, you can use the same alloc/init call and assign the result to a second (different) NSArray* variable or to a different slot in a container object. That should not crash your app, so you might have other problems elsewhere. Even if you assign both new arrays to the same variable, I would not expect a crash, just memory leaks. That said, creating an NSArray in this way is sort of odd. NSArray is a non-mutable type; you can't add any objects to it after it is created. What the line above does is create an empty container that can only remain empty for its entire existence. You either want an NSMutableArray if adding and removing objects is needed, or you should use one of the NSArray factory methods that creates a pre-filled nonmutable array.
     
  4. ATG thread starter macrumors regular

    Joined:
    Aug 7, 2005
    #4
    Oops. I forgot to say that yes they are mutable arrays. So I'm doing this:
    Code:
    NSMutableArray * myArray = [[NSMutableArray alloc] init];
    I am releasing them. The only thing I can think of is my release statements. At the moment I have this:
    Code:
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    NSMutableArray * facArray = [[NSMutableArray alloc] init];
    //code that uses facArray
    [facArray Release]
    
    NSMutableArray * pfacArray = [[NSMutableArray alloc] init];
    //code that uses pfacArray
    [pfacArray Release]
    
    If that code is right I'll have a look for any mistakes in the 'body'.
     
  5. caveman_uk Guest

    caveman_uk

    Joined:
    Feb 17, 2003
    Location:
    Hitchin, Herts, UK
    #5
    What's the error you're getting?

    BTW, 'release' doesn't have a capital 'R'.
     
  6. whooleytoo macrumors 603

    whooleytoo

    Joined:
    Aug 2, 2002
    Location:
    Cork, Ireland.
    #6
    And that's enough to throw an exception, which if not caught...
     
  7. gekko513 macrumors 603

    gekko513

    Joined:
    Oct 16, 2003
    #7
    Have you tried running it in the debugger? When you do you should be able to tell more accurately where it crashes.
     
  8. ATG thread starter macrumors regular

    Joined:
    Aug 7, 2005
    #8
    All my releases have lower-case 'r's
    I'm going to run it in the debugger right now.

    AHA: If I take the init of my second array so it looks like this...
    Code:
    NSMutableArray *pfacArray [NSMutableArray alloc]
    ...it won't crash. This I think means that my problem is with the 'init'. Any ideas? :confused:
     
  9. gekko513 macrumors 603

    gekko513

    Joined:
    Oct 16, 2003
    #9
    The correct init call for mutable array is initWithCapacity: not just init ... as in:
    Code:
    NSMutableArray * pfacArray = [[NSMutableArray alloc] initWithCapacity:100];
    Look in the reference documentation for class XXX under the headline Creating an XXX to find proper ways of instantiating objects of that class. As you can see, an alternative to initWithCapacity would be:
    Code:
    NSMutableArray *pfacArray = [NSMutableArray arrayWithCapacity:100];
    In this last case, as with other methods that return an object, the factory class methods with a '+' return objects that must not be released, since they already have an autorelease pending.
     
  10. ATG thread starter macrumors regular

    Joined:
    Aug 7, 2005
    #10
    Nope. It still crashes. I've tried both of your's, not that I understand your last statement about autoreleasing and class methods. Any other ideas? :confused:
     
  11. gekko513 macrumors 603

    gekko513

    Joined:
    Oct 16, 2003
    #11
    I assume you changed it for both arrays? Can you post the entire method code? Or I can PM my e-mail address to you so that you can mail the entire project to me if you want.
     
  12. ATG thread starter macrumors regular

    Joined:
    Aug 7, 2005
  13. admanimal macrumors 68040

    Joined:
    Apr 22, 2005
    #13
    As someone else pointed out, you do not need to release either of those arrays, because init methods autorelease them, and you have not explicitly retained them. Releasing a variable that has not been retained can cause a crash.

    You can PM me the code if you'd like as well.
     
  14. whooleytoo macrumors 603

    whooleytoo

    Joined:
    Aug 2, 2002
    Location:
    Cork, Ireland.
    #14
    While this may not be the cause of the crash, it is very important to understand the point he was making.

    The difference between the two lines he gave was:

    Code:
    NSMutableArray * pfacArray = [[NSMutableArray alloc] initWithCapacity:100];
    In this case, because you're calling the alloc method to allocate memory for the pfacArray, it's your responsibility to call its release method later to free it - otherwise it'll leak.

    Code:
    NSMutableArray *pfacArray = [NSMutableArray arrayWithCapacity:100];
    In this case, you're not calling alloc (or copy), so it's not your responsibility to call the release method - if you do so, your app may well crash.

    That's because the arrayWithCapacity method is autoreleasing the array it returns to you (i.e. instead of the last line in arrayWithCapacity: being something like "return newArray;" it's probably "return [newArray autorelease];").

    However, if you want to hold on to the pfacArray returned (say, if you need to use it in later methods), you'll need to call it's retain method to ensure it doesn't get freed while you still need it, then call release once you're done with it.

    Code:
    // Create a new array via alloc..init
    - (void) createNewArray1
    {
        NSMutableArray* myArray = [[NSMutableArray alloc] initWithCapacity:10] ;
        
       // Do stuff with myArray
    
       [myArray release] ;
    }
    
    /* Now, what if you want to return that array from that function? You can't release the array before you return it (or you'll be returning nothing!), so how do you make sure it doesn't get leaked? Use autorelease */
    
    - (NSMutableArray*) createNewArray2
        NSMutableArray* myArray = [[NSMutableArray alloc] initWithCapacity:10] ;
        
       // Do stuff with myArray
    
       return [myArray autorelease] ;
    }
    
    /* Or, you could just: */
    - (NSMutableArray*) createNewArray3
        NSMutableArray* myArray = [NSMutableArray arrayWithCapacity:10] ;
        
       // Do stuff with myArray
    
       return myArray;
    }
    
    /* Note, in createNewArray3, you didn't release or autorelease the array. That's because, you didn't create it (via alloc or copy), so you're not responsible for releasing it. */
    
    Hope I've helped and not confused! ;)
     
  15. whooleytoo macrumors 603

    whooleytoo

    Joined:
    Aug 2, 2002
    Location:
    Cork, Ireland.
    #15
    I'm afraid that's not the case, init methods never autorelease the object they return; and thus should always be 'balanced' with a release.
     
  16. caveman_uk Guest

    caveman_uk

    Joined:
    Feb 17, 2003
    Location:
    Hitchin, Herts, UK
    #16
    He's doing an alloc so yes he does need to release it.
     
  17. caveman_uk Guest

    caveman_uk

    Joined:
    Feb 17, 2003
    Location:
    Hitchin, Herts, UK
    #17
    What's wrong with just plain 'init'? It works just fine as it's inherited from NSObject. initWithCapacity is probably faster to add objects to later as there's more preallocated space for the array but both work fine. It's not really helping the guy find his crasher.
     
  18. whooleytoo macrumors 603

    whooleytoo

    Joined:
    Aug 2, 2002
    Location:
    Cork, Ireland.
    #18
    That's right, it's just less efficient, that's all.

    ATG, feel free to post more of the code here so we can look at it.
     
  19. gekko513 macrumors 603

    gekko513

    Joined:
    Oct 16, 2003
    #19
    OK, I might have gotten that wrong then. I only initialize objects with the methods that are explicitly mentioned in the reference document for that class. My motivation for that comes from Java where some classes only have constructors that require arguments. I wasn't confident that a simple init would always be enough. I know for sure that my own classes are usually not initialized properly unless they are called with my own initializers, but I guess that is my fault :eek:
     
  20. gekko513 macrumors 603

    gekko513

    Joined:
    Oct 16, 2003
    #20
    Oh, and I have sent a PM with some help for the original poster. When I plugged the method code into a project of my own I found that it went into an infinite loop and did not really crash on the alloc init statements. So hopefully that has solved the problem.
     
  21. caveman_uk Guest

    caveman_uk

    Joined:
    Feb 17, 2003
    Location:
    Hitchin, Herts, UK
    #21
    Generally in objective-C/Cocoa you override the 'init' method if you have anything special to do for your class having first called [super init] which generally will be the one in NSObject. I don't know about 'initWithCapacity' specifically but most of the 'initWith..' methods probably also call [super init] somewhere along the line.
     

Share This Page