I cannot allocate a nsmutablearray as a class variable [closed] - objective-c

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I was having problem allocating the NSMutableArray in the player class, there is no warning in the compile time when I tried this way in the (id)init method: playerInventory = [[NSMutableArray alloc] init]; But when I run the program, it gives me an error (EXC_BAD_ACCESS). I have checked over and over, but found nothing help. I am new to objective c and I don't have much knowledge in memory management in this language. But seemed that I cannot find the answer after my best effort.
the .h file
#interface Player : NSObject
{
int playerLevel;
int playerExp;
NSMutableArray *playerInventory;
NSString *playerName;
BOOL isLastPlayerExist;
NSData *xmlData;
GDataXMLDocument *_xmlDoc;
}
#property (assign,readwrite) int playerLevel;
#property (retain,readonly) NSString *playerName;
#property (assign,readonly) BOOL isLastPlayerExist;
#property (retain,readwrite) NSMutableArray *playerInventory;
+(Player *)currentPlayer;
-(void)loadXMLFile;
-(void)loadRecentPlayer;
-(void)loadPlayerStats;
-(void)loadPlayerInventory;
-(void)releaseXMLFile;
#end
the .m file , deleted irrelevant implementations.
#implementation Player
static Player *sharedInstance = nil;
#synthesize playerLevel;
#synthesize playerName;
#synthesize isLastPlayerExist;
#synthesize playerInventory;
-(id) init{
self = [super init];
if (self != nil){
playerInventory = [[NSMutableArray alloc] init];
[self loadXMLFile];
[self loadRecentPlayer];
[self loadPlayerStats];
}
return self;
}
-(void) loadXMLFile{
NSString *filePath = [self dataFilePath: NO];
xmlData = [[NSMutableData alloc] initWithContentsOfFile:filePath];
NSError *error;
_xmlDoc = [[GDataXMLDocument alloc] initWithData:xmlData
options:0 error:&error];
}
-(void) loadRecentPlayer{
NSArray *playerInfo = [_xmlDoc.rootElement elementsForName:#"Player"];
GDataXMLElement *currentName = (GDataXMLElement *)[playerInfo objectAtIndex:0];
playerName = currentName.stringValue;
NSLog(#"%#",playerName);
}
-(void) loadPlayerStats{
NSString *xPath;
NSArray *playerInfo;
xPath = [NSString stringWithFormat:#"//Users/Player[Name = \"%#\"]/Level",playerName];
playerInfo = [_xmlDoc.rootElement nodesForXPath:xPath error: nil];
GDataXMLElement *level = (GDataXMLElement *)[playerInfo objectAtIndex:0];
playerLevel = level.stringValue.intValue;
xPath = [NSString stringWithFormat:#"//Users/Player[Name = \"%#\"]/Experience",playerName];
playerInfo = [_xmlDoc.rootElement nodesForXPath:xPath error: nil];
GDataXMLElement *exp = (GDataXMLElement *)[playerInfo objectAtIndex:0];
playerExp = exp.stringValue.intValue;
xPath = [NSString stringWithFormat:#"//Users/Player[Name = \"%#\"]/Inventory/CardID",playerName];
playerInfo = [_xmlDoc.rootElement nodesForXPath:xPath error: nil];
for(id obj in playerInfo){
GDataXMLElement *card = (GDataXMLElement *)obj;
[playerInventory addObject: card.stringValue.intValue];
NSLog(#"%d",card.stringValue.intValue);
}
NSLog(#"%#",playerInventory);
}
+(Player *)currentPlayer{
if (sharedInstance == nil){
sharedInstance = [[self alloc] init];
}
return sharedInstance;
}
- (NSString *)dataFilePath:(BOOL)forSave {
return [[NSBundle mainBundle] pathForResource:#"userData" ofType:#"xml"];
}
#end

change
#synthesize playerInventory = _ playerInventory;
and allocate like following
_playerInventory = [[NSMutableArray alloc] init];

Related

nsmutable array not saving values

My array is not saving the values I put in it...
I am defining my nsmutablearray *arrayClientList in .h file
#interface StartupTableViewController : UIViewController<UITableViewDataSource, UITableViewDelegate>
#property (strong, nonatomic) IBOutlet UITableView *tableView;
#property NSMutableArray *arrayClientList;
#property BOOL boolAddToClient;
//#property (strong, nonatomic) NSMutableArray *arrayAddClient;
#end
in .m file I am initializing like so
- (void)viewDidLoad {
[super viewDidLoad];
//initialize variables
self.arrayClientList = [[NSMutableArray alloc] init];
arraySelectedInformation = [[NSMutableArray alloc] init];
self.boolAddToClient = NO;
NSString *tstring = #"hello";
[self.arrayClientList addObject:tstring];
but then once I get to another method in this same class... the array is nil again. I must be doing something stupid for the array not to hold the values
-(void)viewDidAppear:(BOOL)animated{
//NSLog(#"appeared");
if (self.boolAddToClient) {
NSLog(#"add client to list");
self.boolAddToClient = NO;
[self.tableView reloadData];
}
else{
NSLog(#"startup");
}
}
I am trying to use it in another class
- (IBAction)buttonSubmit:(id)sender {
NSString *userDescription = [[NSString alloc] init];
NSString *userUsername = [[NSString alloc] init];
NSString *userPassword = [[NSString alloc] init];
userDescription = self.textfieldDescription.text;
userUsername = self.textfieldUserID.text;
userPassword = self.textfieldPW.text;
//check to make sure user filled out all fields
if (![userDescription isEqual:#""] && ![userUsername isEqual:#""] && ![userPassword isEqual: #""]){
NSLog(#"correct");
NSArray *arrayVC = self.navigationController.viewControllers;
StartupTableViewController *parentViewController = [arrayVC objectAtIndex:0];
parentViewController.boolAddToClient = YES;
NSMutableArray *arrayNewObjects = [[NSMutableArray alloc] initWithObjects:userDescription, userUsername, userPassword, nil];
NSMutableArray *tarray = parentViewController.arrayClientList;
[tarray addObject:arrayNewObjects];
[parentViewController.arrayClientList addObject:arrayNewObjects];
[self.navigationController popViewControllerAnimated:YES];
}
else{
NSLog(#"something missing");
}
}
Since I can't comment without rep, I must try with answer.
Try this:
In ViewDidLoad do alloc init with Strings you create in implementation and also change if block to this:
#implementation
{
NSString *userDescription;
NSString *userUsername;
NSString *userPassword;
}
-(void)viewDidLoad {
[super viewDidLoad];
NSString *userDescription = [[NSString alloc] init];
NSString *userUsername = [[NSString alloc] init];
NSString *userPassword = [[NSString alloc] init];
}
- (IBAction)buttonSubmit:(id)sender {
if (self.textfieldDescription.text.lenght != 0 && self.textfieldUserID.text.lenght != 0 && self.textfieldPW.text.lenght != 0) {
userDescription = self.textfieldDescription.text;
userUsername = self.textfieldUserID.text;
userPassword = self.textfieldPW.text;
....... and the rest
}
Please comment if it's not working, and I also think that you're not passing the informations right. Try searching an answer on how to pass arrays between TableViewControllers. Good Luck!

issue adding NSMutablearray to other NSMutablearray? [duplicate]

This question already has answers here:
Cannot add items to an NSMutableArray ivar
(4 answers)
Closed 8 years ago.
I'm trying to add NSMutableArray to other NSMutableArray, a mutable array set as instance ivar, but I allways got the array arrayPlayoff empty. Other thing that I have detected, is that when debugging in the attached method, local variables are not shown in the debugger variables section, even selecting "local" option.
-(void)loadGamesPlayoffs{
NSMutableArray *eli1 = [[NSMutableArray alloc] init];
NSMutableArray *eli2 =[[NSMutableArray alloc] init];
NSMutableArray *eli3 = [[NSMutableArray alloc] init];
NSMutableArray *eli4 = [[NSMutableArray alloc] init];
for (NSDictionary *eliminatoria in copaReyArray){
int eli = [[eliminatoria valueForKey:#"eliminatoria"]integerValue];
NSLog(#"eli %d", eli);
if (eli==1){
[eli1 addObject:eliminatoria];
} else if (eli==2){
[eli2 addObject:eliminatoria];
}else if (eli==3){
[eli3 addObject:eliminatoria];
} else if (eli==4){
[eli4 addObject:eliminatoria];
}
}
[arrayPlayOff addObject:eli1];
[arrayPlayOff addObject:eli2];
[arrayPlayOff addObject:eli3];
[arrayPlayOff addObject:eli4];
}
many thanks
If arrayPlayOff is an Instance Variable you could use properties, your .h should look something like this:
#import <UIKit/UIKit.h>
#interface YourClassViewController : UIViewController{
NSMutableArray *arrayPlayOff;
//Some other variables
}
#property (nonatomic, retain) NSMutableArray *arrayPlayOff;
//Some other methods
#end
Then in your .m file you could use:
#implementation YourClassViewController
#synthesize arrayPlayOff;
- (NSMutableArray *)arrayPlayOff{
if(!arrayPlayOff){
arrayPlayOff = [[NSMutableArray alloc] init];
}
return arrayPlayOff;
}
//Your other methods
//Overwrite the dealloc function so you don't have any memory leaks
- (void)dealloc{
[arrayPlayOff release];
[super dealloc];
}
#end
Now you could access your variable as
self.arrayPlayOff
and this way you can be 100% sure that your variable is always initialized.
Your method could look like this (Also you should release your other NSMutableArrays since you are not using after adding them to the arrayPlayOff array):
-(void)loadGamesPlayoffs{
NSMutableArray *eli1 = [[NSMutableArray alloc] init];
NSMutableArray *eli2 =[[NSMutableArray alloc] init];
NSMutableArray *eli3 = [[NSMutableArray alloc] init];
NSMutableArray *eli4 = [[NSMutableArray alloc] init];
for (NSDictionary *eliminatoria in copaReyArray){
int eli = [[eliminatoria valueForKey:#"eliminatoria"]integerValue];
NSLog(#"eli %d", eli);
if (eli==1){
[eli1 addObject:eliminatoria];
} else if (eli==2){
[eli2 addObject:eliminatoria];
}else if (eli==3){
[eli3 addObject:eliminatoria];
} else if (eli==4){
[eli4 addObject:eliminatoria];
}
}
[self.arrayPlayOff addObject:eli1];
[self.arrayPlayOff addObject:eli2];
[self.arrayPlayOff addObject:eli3];
[self.arrayPlayOff addObject:eli4];
//Releasing the NSMutableArrays
[eli1 release];
[eli2 release];
[eli3 release];
[eli4 release];
}

Iterate through an NSMutableArray of Objects

I have a class with the following property and method:
header file below - note I did not copy/paste all code (only pertinant information):
#interface SQLiteDB : NSObject
#property (nonatomic, strong) NSMutableArray *allAccountsArray;
#property (nonatomic, strong) NSString *accountId, *accountName, *accountDescription, *accountTags, *accountPhoto, *accountCreationDate;
+(id) populateAccountObjectWithId:(NSString *)id andName:(NSString *)name andDescription:(NSString *)description andTags:(NSString *)tags andPhoto:(NSString *)photo andCreationDate:(NSString *)creationDate;
#end
implementation file below - note I did not copy/paste all code (only pertinant information):
+(id) populateAccountObjectWithId:(NSString *)id andName:(NSString *)name andDescription:(NSString *)description andTags:(NSString *)tags andPhoto:(NSString *)photo andCreationDate:(NSString *)creationDate
{
SQLiteDB *mySQLiteDB = [[self alloc] init];
mySQLiteDB.accountId = id;
mySQLiteDB.accountName = name;
mySQLiteDB.accountDescription = description;
mySQLiteDB.accountTags = tags;
mySQLiteDB.accountPhoto = photo;
mySQLiteDB.accountCreationDate = creationDate;
return mySQLiteDB;
}
Then, another method in the implementation file fetches all accounts from the SQLite database:
-(id) fetchAccountList
{
// do some database stuff here
// create prepared statement, open database, etc...
allAccountsArray = [[NSMutableArray alloc] init];
while(sqlite3_step(statement) == SQLITE_ROW)
{
NSString *thisAccountId = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement,0)];
NSString *thisAccountName = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 1)];
NSString *thisAccountDescription = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 2)];
NSString *thisAccountTags = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 3)];
NSString *thisAccountPhoto = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 4)];
NSString *thisAccountCreationDate = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 5)];
[allAccountsArray addObject:[SQLiteDB populateAccountObjectWithId:thisAccountId andName:thisAccountName andDescription:thisAccountDescription andTags:thisAccountTags andPhoto:thisAccountPhoto andCreationDate:thisAccountCreationDate]];
}
// error handling code, etc.
// finalize, & close code here...
return allAccountsArray;
}
Now finally the question. In other classes I want to do stuff with the array of objects that this returns. For instance I would do this in a TableVeiw controller:
-(void)loadView
{
[super loadView];
mySQLiteDB = [[SQLiteDB alloc] init];
allAccountsArray = [mySQLiteDB fetchAccountList];
}
I would use this later to for instance populate the table list in the cellForRowAtIndexPath method. Perhaps each cell of the table would contain the accountName, accountDescription, and accountCreationDate. I do not however know how to access that name, desc, date from within the array of objects...
This obviously produces an error:
cell.textLabel.text = [allAccountsArray objectAtIndex:indexPath.row];
because the object at "row" is an "object" containing name, desc, date, etc...
So Stackoverflow, I ask you... How do I accomplish getting the object variables at each element of the array?
You should be able to do something as simple as this:
SqliteDB *mySqliteDB = (SQliteDB *)[allAccountsArray objectAtIndex:indexPath.row];
NSString *myText = mySqliteDB.thisAccountID;
myText = [myText stringByAppendingString:mySqliteDB.thisAccountName];
.... etc.
cell.textLabel.text = myText;
I think enumerateObjects:usingBlock: is what you want for iterating, i.e. enumerating, objects. You might have missed it because it's in the superclass.

Something is wrong with singleton...unable adding a child because it is nil

I use a singleton the first time and I don't really know how to implement it...
Ok I need to explain some things:
In Hexagon.h (which inherits from CCNode) I want to create multiple sprites (here referred to as "hexagons"). However, they are not added to the scene yet. They are being added in the HelloWorldLayer.m class by calling Hexagon *nHex = [[Hexagon alloc]init]; . Is that correct ? Is it then iterating through the for loop and creating all hexagons or only one ?
Well anyways, I have a singleton class which has to handle all the public game state information but retrieving is not possible yet.For instance I cannot retrieve the value of existingHexagons, because it returns (null) objects. Either I set the objects wrongly or I am falsely retrieving data from the singleton. Actually, I would even appreciate an answer for one of these questions. Please help me. If something is not clear, please add a comment and I'll try to clarify it.
What I have right now is the following:
GameStateSingleton.h
#import <Foundation/Foundation.h>
#interface GameStateSingleton : NSObject{
NSMutableDictionary *existingHexagons;
}
+(GameStateSingleton*)sharedMySingleton;
-(NSMutableDictionary*)getExistingHexagons;
#property (nonatomic,retain) NSMutableDictionary *existingHexagons;
#end
GameStateSingleton.m
#import "GameStateSingleton.h"
#implementation GameStateSingleton
#synthesize existingHexagons;
static GameStateSingleton* _sharedMySingleton = nil;
+(GameStateSingleton*)sharedMySingleton
{
#synchronized([GameStateSingleton class])
{
if (!_sharedMySingleton)
[[self alloc] init];
return _sharedMySingleton;
}
return nil;
}
+(id)alloc
{
#synchronized([GameStateSingleton class])
{
NSAssert(_sharedMySingleton == nil, #"Attempted to allocate a second instance of a singleton.");
_sharedMySingleton = [super alloc];
return _sharedMySingleton;
}
return nil;
}
-(id)init {
self = [super init];
if (self != nil) {
}
return self;
}
#end
Hexagon.m
-(CCSprite *)init{
if( (self=[super init])) {
NSString *mainPath = [[NSBundle mainBundle] bundlePath];
NSString *levelConfigPlistLocation = [mainPath stringByAppendingPathComponent:#"levelconfig.plist"];
NSDictionary *levelConfig = [[NSDictionary alloc] initWithContentsOfFile:levelConfigPlistLocation];
NSString *currentLevelAsString = [NSString stringWithFormat:#"level%d", 1];
NSArray *hexPositions;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad){
hexPositions = [[levelConfig valueForKey:currentLevelAsString] valueForKey:#"hexpositionIpad"];
}
else{
hexPositions = [[levelConfig valueForKey:currentLevelAsString] valueForKey:#"hexpositionIphone"];
}
NSString *whichType = [NSString stringWithFormat:#"glass"];
CGSize screenSize = [CCDirector sharedDirector].winSize;
if ([whichType isEqualToString:#"stone"]){
hexagon = [CCSprite spriteWithFile:#"octagonstone.png"];
}else if([whichType isEqualToString: #"glass"]){
hexagon = [CCSprite spriteWithFile:#"octagoncolored1.png"];
}else if([whichType isEqualToString: #"metal"]){
hexagon = [CCSprite spriteWithFile:#"octagonmetal.png"];
}
NSMutableDictionary *eHexagons =[[GameStateSingleton sharedMySingleton] getExistingHexagons];
for (int i=0;i < [hexPositions count];i++){
CGPoint location = CGPointFromString([hexPositions objectAtIndex:i]);
CGPoint nLocation= ccp(screenSize.width/2 + 68 * location.x,screenSize.height/2 + 39 * location.y);
NSString *aKey = [NSString stringWithFormat:#"hexagon%d",i];
hexagon =[CCSprite spriteWithFile:#"octagoncolored1.png"];
hexagon.position = nLocation;
[eHexagons setObject:hexagon forKey:aKey];
[self addChild:[eHexagons valueForKey:aKey] z:3];
[[GameStateSingleton sharedMySingleton]setExistingHexagons:eHexagons];
}
NSLog(#"these are the existinghexagons %#", existingHexagons);
//This returns a dictionary with one (null) object
}
return hexagon;
}
HelloWorldLayer.m -> -(id)init method
Hexagon *nHex = [[Hexagon alloc]init];
First of all, it returns null because the existingHexagons array has never been initialized in the first place. Go to the init function of your singleton and add:
existingHexagons = [[NSMutableArray alloc]init];
As for your For Loop question, I did not get it. I recommend making one StackOverflow question per query instead of putting two in one.

Write custom object to .plist in Cocoa

I am blocking into something and I am sure it is too big.
I have a custom object that look like this
#interface DownloadObject : NSObject <NSCoding>{
NSNumber *key;
NSString *name;
NSNumber *progress;
NSNumber *progressBytes;
NSNumber *size;
NSString *path;
}
#property (copy) NSNumber *key;
#property (copy) NSString *name;
#property (copy) NSNumber *progress;
#property (copy) NSNumber *size;
#property (copy) NSString *path;
#property (copy) NSNumber *progressBytes;
-(id)initWithKey:(NSNumber *)k name:(NSString *)n progress:(NSNumber *)pro size:(NSNumber *)s path:(NSString *)p progressBytes:(NSNumber *)pb;
#end
And the implementation
#implementation DownloadObject
#synthesize size, progress, name, key, path, progressBytes;
-(id)initWithKey:(NSNumber *)k name:(NSString *)n progress:(NSNumber *)pro size:(NSNumber *)s path:(NSString *)p progressBytes:(NSNumber *)pb
{
self.key = k;
self.name = n;
self.progress = pro;
self.size = s;
self.path = p;
self.progressBytes = pb;
return self;
}
-(id) initWithCoder: (NSCoder*) coder {
if (self = [super init]) {
self.key = [[coder decodeObjectForKey:#"Key"] retain];
self.name = [[coder decodeObjectForKey:#"Name"] retain];
self.progress = [[coder decodeObjectForKey:#"Progress"] retain];
self.size = [[coder decodeObjectForKey:#"Size"] retain];
self.path = [[coder decodeObjectForKey:#"Path"] retain];
self.progressBytes = [[coder decodeObjectForKey:#"ProgressBytes"]retain];
}
return self;
}
-(void) encodeWithCoder: (NSCoder*) coder {
[coder encodeObject:self.key forKey:#"Key"];
[coder encodeObject:self.name forKey:#"Name"];
[coder encodeObject:self.progress forKey:#"Progress"];
[coder encodeObject:self.size forKey:#"Size"];
[coder encodeObject:self.path forKey:#"Path"];
[coder encodeObject:self.progressBytes forKey:#"ProgressBytes"];
}
-(void)dealloc
{
[key release];
[name release];
[size release];
[progress release];
[path release];
[progressBytes release];
[super dealloc];
}
#end
As you can see it implement NSCoding (I think so, NSObject does not conform to NSCoding). Now when I try to do something like that just to test
downloadArray = [[[NSMutableArray alloc]init]retain];
NSNumber *number = [NSNumber numberWithInt:10];
DownloadObject *object = [[DownloadObject alloc]initWithKey:number name:#"hey" progress:number size:number path:#"hey" progressBytes:number];
[downloadArray addObject:object];
[object release];
[downloadArray writeToFile:path atomically:YES];
downloadArray is a NSMutableArray. My plist read/write is fine, the path is located in the application support and when I log it show the plist path.
But it just does not write the array to the plist, any idea ?
Property list files can only store basic data types and cannot contain custom objects. You need to convert your object to an NSData object if you want it to be written to the plist. You can do this with NSKeyedArchiver, which will encode an object which conforms to the NSCoding protocol into an NSData object.
DownloadObject *object = [[DownloadObject alloc]initWithKey:number name:#"hey" progress:number size:number path:#"hey" progressBytes:number];
NSData* objData = [NSKeyedArchiver archivedDataWithRootObject:object];
[downloadArray addObject:objData];
[object release];
When you want to reconstruct your object from the NSData object, you use NSKeyedUnarchiver:
NSData* objData = [downloadArray objectAtIndex:0];
DownloadObject* object = [NSKeyedUnarchiver unarchiveObjectWithData:objData];
You also have several memory leaks in your code. In your -initWithCoder: method, you should not be using accessors to set the value of the ivars, you should just set the ivars directly, like so:
key = [[coder decodeObjectForKey:#"Key"] copy];
You are calling -retain and then using the accessor which is specified as copy, which will mean your object has a retain count of 2 and will not be released. In general you should avoid using accessors in init methods.
Also, in the code where you allocate your downloadArray object, you are calling -alloc and then -retain on the object, which will leave it with a retainCount of 2. You should re-read the Objective-C Memory Management Guidelines.
This works for me:
NSMutableData *data = [[NSMutableData alloc] init];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
[archiver encodeObject:highScoreArray forKey:kHighScoreArrayKey];
[archiver finishEncoding];
[data writeToFile:[self dataFilePath] atomically:YES];
[data release];
[archiver release];
BOOL flag = false;
ObjectFileClass *obj = [yourMutableArray objectAtIndex:0];
//TO Write Data . . .
NSData* archiveData = [NSKeyedArchiver archivedDataWithRootObject:obj.title];
flag =[archiveData writeToFile:path options:NSDataWritingAtomic error:&error];
}
if (flag) {
NSLog(#"Written");
//To Read Data . . .
NSData *archiveData = [NSData dataWithContentsOfFile:path];
id yourClassInstance = [NSKeyedUnarchiver unarchiveObjectWithData:archiveData]; // choose the type of your class instance . . .
NSLog(#"%#",yourClassInstance);
}else{
NSLog(#"Not Written");
}