开发者

NSMutableArray count keeps changing

I have too much code to know which i need to quote here, but in my app delegate I have an NSMutableArray. Then in another class, it creates a new entry to the NSMutableArray but upon passing back to another class which should use that to display something on screen, it doesn't display anything. Putting an NSLog for the NSMutableArray count at the end of the class creating it displays the number 1, and then putting the same NSLog code at the start of the class which is meant to use that returns 0.

Any ideas why this is?

EDIT: Ok, i'll try and include all related code..

app delegate.h:

@interface palettesAppDelegate : NSObject <UIApplicationDelegate> {
 NSMutableArray *colourPalettesContainer;

}
@property (assign, readwrite) NSMutableArray *colourPalettesContainer;
@end

app delegate.m:

#import "palettesAppDelegate.h"

@implementation palettesAppDelegate

@synthesize colourPalettesContainer;

- (void)dealloc {
    [colourPalettesContainer release];
    [super dealloc];
}


@end

Homeview.h:

#import <UIKit/UIKit.h>
#import "HandlingPalettes.h"

@interface HomeView : UIViewController {

    HandlingPalettes *handlingPalettes;

}


@end

Homeview.m:

#import "HomeView.h"
#import <QuartzCore/QuartzCore.h>


@implementation HomeView


- (void)viewDidLoad {
    [super viewDidLoad];
handlingPalettes = [[HandlingPalettes alloc] init];

    [handlingPalettes newPalette];

}

-(void)viewWillAppear:(BOOL)animated {


    NSLog(@"view will appear: %i", [dataCenter.colourPalettesContainer count]);
    int numberOfExisting = [dataCenter.colourPalettesContainer count];

}

- (void)dealloc {
    [handlingPalettes release];
    [super deallo开发者_运维问答c];
}


@end

HandlingPalettes.h:

#import <UIKit/UIKit.h>

@interface HandlingPalettes : UIViewController {

}


-(void)newPalette;



@end

HandlingPalettes.m:

#import "HandlingPalettes.h"
#import "HomeView.h"
#import "palettesAppDelegate.h"



@implementation HandlingPalettes


-(void)newPalette {

    palettesAppDelegate *dataCenter = (palettesAppDelegate *)[[UIApplication sharedApplication] delegate];

    //If this is the first palette
    if (dataCenter.colourPalettesContainer == nil) {
    dataCenter.colourPalettesContainer = [[NSMutableArray alloc] init];
    }
    //Add a new palette

        [dataCenter.colourPalettesContainer addObject:@"Test1", @"Test2", nil];


    NSLog(@"Handling:    %i", [dataCenter.colourPalettesContainer count]);


}- (void)dealloc {
   [super dealloc];
}


@end


Your main mutablearray is in your app delegate. So, see what happens if in EVERY METHOD that you want to access the array you have the line to set up the app delegate relationship

    palettesAppDelegate *dataCenter = (palettesAppDelegate *)[[UIApplication sharedApplication] delegate];

Now, when you call the dataCenter object you will be referencing the App Delegate and your program will find the array.

You may also find that you will need to have an #import "palettesAppDelegate.h" in each object that is going to reference the App Delegate.

Note, just adding the app delegate code is not necessarily the proper way to deal with this issue from an architectural standpoint. But if it works you at least know the answer to your original question.


I suspect the problem is ultimately related to confused memory management of the colourPalettesContainer member. You release it in the app delegate's dealloc method, but that class never retains it! It would be much cleaner if you'd follow Apple's memory management guidelines: your classes should only release objects that they own (i.e., that they themselves retained earlier). For example, you can do this by declaring the array's property retain:

@property (retain) NSMutableArray *colourPalettesContainer;

(To prevent leaking the array, you'll also need to release or autorelease it in the newPalette method. Retain and release should always come in close pairs.)

But even better, why not simply create the array in the app delegate's init method, or in its accessor (if for some reason you want to continue creating it only on its first use)? Unless you want to replace all palettes at once, there is no reason to let the array be assigned to from outside the app delegate.

@interface PalettesAppDelegate : NSObject <UIApplicationDelegate> {
@private
    NSMutableArray *colourPalettesContainer;
}
@property (readonly) NSMutableArray *colourPalettesContainer;
@end

@implementation PalettesAppDelegate

- (NSMutableArray *)colourPalettesContainer {
    if (colourPalettesContainer == nil) {
        colourPalettesContainer = [[NSMutableArray alloc] init];
    return colourPalettesContainer;
}

- (void)dealloc {
    [colourPalettesContainer release];
    [super dealloc];
}
@end

To make the design even cleaner, change the type of the colourPalettesContainer property to NSArray * and add an -addPalette: method to the app delegate. (It is rarely a good idea to publicly expose a mutable array inside a class.) You can then simply get rid of -newPalette in HandlingPalettes. (If you want to have all your palette-handling methods in HandlingPalettes, then simply move the array there. If you need to access the palettes from random places in your app, then you can simply put a retained reference to your HandlingPalettes object in the app delegate.)

Once you clean up the object ownership mess, the count mismatch will either resolve itself "by magic" or the cause will likely become much more obvious. In the latter case, check that the HomeView's dataCenter is actually the same object as the one in HandlingPalettes. (You omitted how HomeView gets its reference — are you sure you aren't creating another instance of the app delegate by accident?)

(By the way, you probably meant to use -addObjects:, not -addObject: in newPalette. Note also that all class names should be capitalized, with no exceptions: i.e., always use PalettesAppDelegate, never palettesAppDelegate. If for some reason Xcode's project template created it like that, simply rename the class. Lowercase class names are much too easy to confuse with variable names. Also, try to find better names in general: e.g., instead of HandlingPalettes, I'd use PalettesViewController (to reflect the fact that it is a subclass of UIViewController); and instead of dataCenter, I'd rather just choose appDelegate.)


I would be inclined to get rid of the newPalette method, and instead create a getter method for colourPalettesContainer in your app delegate. ie:

appdelegate.h

@interface PalettesAppDelegate : NSObject <UIApplicationDelegate> {
   NSMutableArray *colourPalettesContainer;

} 
@property (non-atomic, retain) NSMutableArray *colourPalettesContainer;
@end

@implementation palettesAppDelegate

appdelegate.m

#import "appdelegate.h"
@synthesize colourPalettesContainer;
- (NSMutableArray *) colourPalettesContainer{
    if(colourPalettesContainer==nil){
        colourPalettesContainer=[[NSMutableArray alloc] init];
    }
    return colourPalettesContainer;
}
- (void)dealloc {
    [colourPalettesContainer release];
    [super dealloc];
}
@end

you should then be able to add items by calling

[appDelegate.colourPalettesContainer addObject:object];
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜