0

I create a NSMutableArray that I need as long as my app lives, lets call it suseranArray, just after the @implementation of my main class. This Array will hold several objects of a class called Vassal. A Vassal is simply:

1) A NSMutableString 2) Another NSMutableString 3) A NSMutableArray 4) Another NSMutable Array

Each Vassal created is also needed for the life of the app, and they never change.

These objects are made as (retain) properties in an .h file, synthesized in the .m file, and each given an alloc+init whenever the object Vassal is created during the init function. Each vassal has data filled in and stored in the suzerain Array. the 3rd item always has several elements, and after a bug appeared, I put a line to check if it is ever empty, but it never is, and life is good.

Now, later on when a certain Vassal object is needed, we try to access its 3rd property to fetch the data in there, and sometimes that array empty... I checked to see if it disappeared somehow, but it is always there on the debug, carrying a nice address like 0x2319f8a0 which makes sense since the NSMutableString just above it is at address 0x2319fb40 - (I was expecting 00000000 after a lot of headache). What is happening? I my head, I am creating an RETAINed objects, which retains data put in by default, and that object is put inside another, but somehow the data inside the array vanishes. What possible scenario could lead to this? Thank you for your time :)

Note: the last array currently just holds one item at this stage of development, and curiously enough, that one item is never missing, despite the two arrays being 'brothers'

Vassal.h
@interface Vassal : NSObject
@property  (retain) NSMutableString *wordBody;
@property  (retain) NSMutableString *wordCode;
@property   (retain) NSMutableArray *wordRelations;
@property   (retain) NSMutableArray *wordLinks;
@end

Vassal.m
@implementation Vassal:NSObject
@synthesize wordBody;
@synthesize wordCode;
@synthesize wordRelations;
@synthesize wordLinks;
-(NSObject*) init
{
    if(self=[super init])
    {
        wordBody=[[NSMutableString alloc] init];
        wordCode=[[NSMutableString alloc] init];
        wordRelations=[[NSMutableArray alloc] init];
        wordLinks=[[NSMutableArray alloc] init];
    }
    return self;
}

//Somewhere in Suseran:
-(void)fillStuff
{
    ...
    Vassal *vassal=[Vassal new];
    for (int i=0;i<[originalDataString length];i++)
    {
        ...
        [vassal.wordRelations addObject:anItem];
        ...
    }
    int errorTest=[vassal.wordRelations count];
    if (errorTest==0)
    {
         //breakpoint here. Program NEVER comes here
    }
    [bigArrayOfVassals addObject:vassal];
}
//these arrays are never touched again but here:
-(void) getVassalstuff:(NSMutableString*)codeOfDesiredVassal
{
    Vassal *aVassal;
    for (int i=0;i<[bigArrayOfVassals count];i++)
    {
            aVassal=bigArrayOfVassals[i];
            if ([codeOfDesiredVassal isEqualToString:aVassal.wordCode)
            {
                  int errorTest=[aVassal.wordRelations count];
                  if (errorTest==0)
                  {
                         //yay! this breakpoint sometimes is hit, sometimes not,
                         //depending on code's mood. Why is this happening to me? :,(
                  }
            }
    }
}
6
  • 1
    A line of code is better than five lines of explanations :-) Commented Aug 22, 2013 at 0:39
  • There is no reason to expect that "close" items would have "close" addresses. The heap doesn't work that way. Commented Aug 22, 2013 at 0:42
  • (My guess is that you have a copy of that array pointer somewhere else, and you are modifying the array through that pointer copy. You need to understand the difference between a pointer (address) and the object itself (the house at that address). You can have many pointers to a given object, and modifications made through one are seen by all.) Commented Aug 22, 2013 at 0:44
  • There :) hope it's clearer now. Sorry I didnt type any code before, thought would be better to explain. Commented Aug 22, 2013 at 1:14
  • I can't see the declaration for bigArrayOfVassals Commented Aug 22, 2013 at 1:50

1 Answer 1

1

I see that that you have properties that are mutable (which is itself a bad idea except for specific cases) and that you are retaining them.

Mutability means that if you have set the array as a property based on some other array, and if that original array is changed, the array in your property is also changed. It may be, and I don't know because you haven't shown any code, that you are emptying the original array, and thus changing the array you have as a property

Solutions:

My preferred solution is to use the immutable versions of these classes for your properties; NSString, NSArray and instead of retain use copy

A second solution is to leave the properties as mutable, but write a custom setter for each of them that stores a mutableCopy of the object that you pass in.

In both of these cases, your property will be a copy of the object used to set the property, so that if the object is changed outside of your class it will not affect your class's properties.

edited to add, after a comment

If you declare your property as

@property (copy) NSArray wordRelations;

Then simply writing

vassal wordArray = tempArray;

will do the same thing and is cleaner and more readable..

Sign up to request clarification or add additional context in comments.

3 Comments

Will try all that, thank you very much. No data is changed after the initial value is filled in. The arrays are just a copy of a data file that never changes after they are filled. As a matter of fact I was this close to just reading the info from the file instead of using the arrays - a 'make it work now, optimize later' thingy :)
If they are never changing after you add them - there is no point having them as mutable.
Well, I changed wordRelations to NSArray. No more bugs so far :) Thanks man :D (And as a side note for the traveller who stumbles here with a similar problem, I created a NSMutableArray *temp, loaded all the data there, and then what does the trick is vassal.wordRelations=[NSArray arrayWithArray:tempArray] pretty brute force eh? ;)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.