I think I am hallucinating. I am trying to add some persistence to my Concentration-lke game. I would like to keep track of high scores. I got this partially working for a little while today and now it has all gone kablooie (I think that is the correct iOS terminology). Now, my allHighScores NSMutablearray suddenly becomes a CALayer. I am using NSKeyed Archiving. I have a break point in my file before allHighScores gets loaded with data. When stepping through the application, allHighScores exists as an NSMutableArray - then, at the next step, it suddenly becomes a CA Layer. Huh?
-(id)init
{
self = [super init];
if (self) {
NSString *path = [self flipScoreArchivePath];
NSLog(#"Path is %#", path);
allHighScores = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
if (!allHighScores) {
allHighScores = [[NSMutableArray alloc] init];
}
}
return self;
}
+(FlipHighScoreStore *)sharedStore {
static FlipHighScoreStore *sharedStore = nil;
if (!sharedStore) {
sharedStore = [[super allocWithZone:nil]init];
}
return sharedStore;
}
Somehow, calling NSKeyedUnarchiver changes my allHighScores from an NSMutableArray into a CALayer. I am very confused.
I tried adding a retain to the unarchiving instruction, but that didn't help.
Here is my encoding/decoding code:
-(void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:self.themeChosen forKey:#"themeChosen"];
[aCoder encodeInt:self.highScore forKey:#"highScore"];
[aCoder encodeInt:self.scoreStartLevel forKey:#"scoreStartLevel"];
[aCoder encodeInt:self.scoreFinishLevel forKey:#"scoreFinishLevel"];
[aCoder encodeObject:scoreDateCreated forKey:#"scoreDateCreated"];}
-(id)initWithCoder:(NSCoder *)aDecoder {
if (self) {
self.themeChosen = [aDecoder decodeObjectForKey:#"themeChosen"];
self.highScore = [aDecoder decodeIntForKey:#"highScore"];
self.scoreStartLevel = [aDecoder decodeIntForKey:#"scoreStartLevel"];
self.scoreFinishLevel = [aDecoder decodeIntForKey:#"scoreFinishLevel"];
scoreDateCreated = [aDecoder decodeObjectForKey:#"scoreDateCreated"];
}
return self;}
UPDATE: The program crashes when a "highscores.archive" file already exists and a save is called again. I can launch the app, look at the high scores - they are there and retrieved happily, but the save code:
-(BOOL)saveHighScores {
NSString *path = [self flipScoreArchivePath];
return [NSKeyedArchiver archiveRootObject:allHighScores toFile:path];}
causes a EXC_BAD_ACCESS. The path is right, so somehow the allHighScores isn't.
The problem here is you aren't retaining the results of the unarchiving. According to the Basic Memory Management Rules, a method by the name of +unarchiveObjectWithFile: will return an autoreleased object. As such, since you are placing it into an ivar, you need to retain this object, or it will get deallocated out from under you.
Although in your case, since you want a mutable array, you actually need to call -mutableCopy since NSKeyedUnarchive will just give you an immutable array.
-(id)init {
if ((self = [super init])) {
NSString *path = [self flipScoreArchivePath];
NSLog(#"Path is %#", path);
allHighScores = [[NSKeyedUnarchiver unarchiveObjectWithFile:path] mutableCopy];
if (!allHighScores) {
allHighScores = [[NSMutableArray alloc] init];
}
}
return self;
}
Your -initWithCoder: isn't calling super. You need to say
if ((self = [super initWithCoder:aDecoder])) {
Have you tried this?
-(id)init {
if ((self = [super init])) {
NSString *path = [self flipScoreArchivePath];
NSLog(#"Path is %#", path);
allHighScores = [[NSKeyedUnarchiver unarchiveObjectWithFile:path] mutableCopy];
if (!allHighScores) {
allHighScores = [[NSMutableArray alloc] init];
}
// All-important new line....
[self setAllHighScores:allHighScores];
}
return self;
}
Edit/Update:
So, here's two versions of what I actually intended in the above example (I'm assuming here that his ivar allHighScores has a corresponding property):
-(id)init {
if ((self = [super init])) {
NSString *path = [self flipScoreArchivePath];
NSLog(#"Path is %#", path);
self.allHighScores = [[NSKeyedUnarchiver unarchiveObjectWithFile:path] mutableCopy];
if (!self.allHighScores) {
self.allHighScores = [[NSMutableArray alloc] init];
}
}
return self;
}
This is the way I'd actually do it:
-(id)init {
if ((self = [super init])) {
NSMutableArray *arr = [[NSKeyedUnarchiver unarchiveObjectWithFile:[self flipScoreArchivePath]] mutableCopy];
if (!arr) arr = [[NSMutableArray alloc] init];
[self setAllHighScores:arr];
}
return self;
}
Related
I have a custom NSCoding class which stores and retrieves itself when necessary. However, it doesn't feed data to my table view until giving one entry to the array of custom Person objects inside it and restarting the app, then giving another. The first one disappears, however.
After that, it appears to load okay.
Here is the implementation of the class
#import "DataStorage.h"
#implementation DataStorage
#synthesize arrayOfPeople = _arrayOfPeople;
+ (DataStorage *)sharedInstance
{
static DataStorage *state = nil;
if ( !state )
{
NSData *data =[[NSUserDefaults standardUserDefaults] objectForKey:#"DataStorageBank"];
if (data)
{
state = [NSKeyedUnarchiver unarchiveObjectWithData:data];
}
else
{
state = [[DataStorage alloc] init];
}
}
return state;
}
- (instancetype)initWithCoder:(NSCoder *)decoder
{
self = [self init];
if (self) {
if ([decoder decodeObjectForKey:#"DataStoragePeopleArray"]) {
_arrayOfPeople = [[decoder decodeObjectForKey:#"DataStoragePeopleArray"] mutableCopy];
} else {
_arrayOfPeople = [[NSMutableArray alloc] init];
}
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:_arrayOfPeople forKey:#"DataStoragePeopleArray"];
}
- (void)save
{
NSData *appStateData = [NSKeyedArchiver archivedDataWithRootObject:self];
[[NSUserDefaults standardUserDefaults] setObject:appStateData forKey:#"DataStorageBank"];
}
#end
I add objects to the _arrayOfPeople like so:
Person *person = [[Person alloc] initWithFirstName:firstName personSurname:surname personCompay:company personPosition:position personEmail:email personMobile:mobile personProduct:product];
[[DataStorage sharedInstance].arrayOfPeople addObject:person];
[[DataStorage sharedInstance] save];
And load them into the table view by this:
Person *personAtIndex = [[DataStorage sharedInstance].arrayOfPeople objectAtIndex:indexPath.row];
[_arrayOfPeople addObject:personAtIndex];
cell.textLabel.text = personAtIndex.firstName;
cell.detailTextLabel.text = personAtIndex.surname;
Loading them in to the table view is in the method
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
It looks like you only initialize _arrayOfPeople in initWithCoder:. However, if your data does not exist in user defaults already, you use state = [[DataStorage alloc] init] to initialize your shared instance. This does not call initWithCoder: so _arrayOfPeople is nil until after you save and load again, when it is finally initialized as [[NSMutableArray alloc] init]. To fix this, move _arrayOfPeople = [[NSMutableArray alloc] init] out of initWithCoder: and into init. (You could alternatively move it into sharedInstance, but it makes more sense in init since it is not specific to configuring the shared instance.)
Unrelated, but also make sure you synchronize.
- (void)save
{
NSData *appStateData = [NSKeyedArchiver archivedDataWithRootObject:self];
[[NSUserDefaults standardUserDefaults] setObject:appStateData forKey:#"DataStorageBank"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
In creating a login screen with static logins I'm trying to store them privately in the following class implementation. When a button creates IONServer objects I initialize it with the function -(void)login:(NSString *)username password:(NSString *)pw and pass it two UITextField.text strings.
If you notice in the init I am testing stuff with NSLog but at every breakpoint it seems like the storedLogins NSMutable array is nil.
IONServer.m
#import "IONServer.h"
#import "IONLoginResult.h"
#interface IONServer ()
#property (nonatomic) NSMutableArray *storedLogins;
#end
#implementation IONServer
-(void)createStoredLogins
{
NSArray *firstUser = #[#"user1",#"pass1"];
NSArray *secondUser = #[#"user2",#"pass2"];
[self.storedLogins addObject:firstUser];
[self.storedLogins addObject:secondUser];
}
-(instancetype)init {
self = [super init];
if (self) {
[self createStoredLogins];
NSLog(#"Stored logins: %#", _storedLogins);
NSLog(#"Stored user: %#", _storedLogins[0][0]);
}
return self;
}
-(void)login:(NSString *)username password:(NSString *)pw
{
NSArray *logins = [[NSArray alloc]initWithArray:_storedLogins];
for (int i = 0; i < [logins count]; i++) {
if (username == logins[i][0] && pw == logins[i][1]) {
IONLoginResult *result = [[IONLoginResult alloc] initWithResult:YES errorMessage:#"Success!"];
self.result = result;
break;
} else {
IONLoginResult *result = [[IONLoginResult alloc] initWithResult:NO errorMessage:#"Error!"];
self.result = result;
}
}
}
-(void)logout
{
}
#end
You need to initialize the array:
-(instancetype)init {
self = [super init];
if (self) {
_storedLogins = [[NSMutableArray alloc] init];
[self createStoredLogins];
NSLog(#"Stored logins: %#", _storedLogins);
NSLog(#"Stored user: %#", _storedLogins[0][0]);
}
return self;
}
I'm using a singleton class (contactStorage) and a data model (contactModel) to store a list of contacts. I have created a contact object in my viewdidload of my root view controller and attempted to add it to the NSMutableArray but it will not "stick". I have logged the incoming object inside the addContact procedure and it produces accurate output, however, the addObject:c does not add it to the array. Any insight on this?
#import "contactListViewController.h"
#import "contactDetailScreenViewController.h"
#import "ContactModel.h"
#import "contactStorage.h"
#interface contactListViewController ()
#end
#implementation contactListViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
ContactModel* c = [[ContactModel alloc] initWithfName:#"Mike" andlName:#"Deasy" andEmail:#"mid31#pitt.edu" andPhone:#"4127154194"];
[c logContact];
[[contactStorage shared]addContact:c];
[[contactStorage shared]saveToFile];
[c release];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
The code for my singleton:
//
// contactStorage.m
// contactList
//
// Created by dev on 10/23/13.
// Copyright (c) 2013 Deasy, Michael William. All rights reserved.
//
#import "contactStorage.h"
#implementation contactStorage
{
}
#synthesize cList = _cList;
static contactStorage* _myOnlyInstance = nil;
#pragma mark Storage Methods
-(void)addContact: (ContactModel*) c
{
[c logContact];
[self.cList addObject:c];
NSLog(#"%#", _cList);
}
-(ContactModel*)getContact: (NSIndexPath*) index
{
return [self.cList objectAtIndex:index.row];
}
-(NSMutableArray*)deleteContact: (NSIndexPath*) index
{
[self.cList removeObjectAtIndex:index.row];
return self.cList;
}
-(NSMutableArray*)getAllContacts
{
return self.cList;
}
-(void)saveToFile
{
NSString* path = [[self documentsPath] stringByAppendingPathComponent:#"data.txt"];
NSLog(#"%#",path);
[_cList writeToFile:path atomically:YES];
NSLog(#"%#", self.cList);
}
#pragma mark Singleton Create
-(id)init
{
self = [super init];
if (self)
{
NSLog(#"Initing the array");
_cList = [[NSMutableArray alloc] init];
}
return self;
}
+(contactStorage*)shared
{
if (_myOnlyInstance == nil)
{
_myOnlyInstance = [[contactStorage alloc] init];
}
return _myOnlyInstance;
}
-(NSString*) documentsPath
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
return documentsDir;
}
#end
The code for my contactModel:
//
// ContactModel.m
// contactList
//
// Created by dev on 10/23/13.
// Copyright (c) 2013 Deasy, Michael William. All rights reserved.
//
#import "ContactModel.h"
#implementation ContactModel
{
}
#synthesize fName = _fName;
#synthesize lName = _lName;
#synthesize email = _email;
#synthesize phone = _phone;
-(void)logContact
{
NSLog(#"%#", self.fName);
NSLog(#"%#", self.lName);
NSLog(#"%#", self.email);
NSLog(#"%#", self.phone);
}
-(void)dealloc
{
[_fName release];
[_lName release];
[_email release];
[_phone release];
[super dealloc];
}
-(id) initWithfName: (NSString*) fName
andlName: (NSString*) lName
andEmail: (NSString*) email
andPhone: (NSString*) phone
{
self = [super init];
_fName = [[NSString alloc] initWithString:fName];
_lName = [[NSString alloc] initWithString:lName];
_email = [[NSString alloc] initWithString:email];
_phone = [[NSString alloc] initWithString:phone];
return self;
}
#end
NSLog Output:
2013-10-24 12:50:35.573 contactList[3097:a0b] Mike
2013-10-24 12:50:35.574 contactList[3097:a0b] Deasy
2013-10-24 12:50:35.575 contactList[3097:a0b] mid31#pitt.edu
2013-10-24 12:50:35.575 contactList[3097:a0b] 4127154194
2013-10-24 12:50:35.576 contactList[3097:a0b] Initing the array
2013-10-24 12:50:35.576 contactList[3097:a0b] Mike
2013-10-24 12:50:35.576 contactList[3097:a0b] Deasy
2013-10-24 12:50:35.577 contactList[3097:a0b] mid31#pitt.edu
2013-10-24 12:50:35.577 contactList[3097:a0b] 4127154194
2013-10-24 12:50:35.578 contactList[3097:a0b] (
"<ContactModel: 0x8d72720>"
)
2013-10-24 12:50:35.578 contactList[3097:a0b] /Users/dev/Library/Application Support/iPhone Simulator/7.0/Applications/7CFD98F0-C502-49E5-953B-FD43B61EDC38/Documents/data.txt
2013-10-24 12:50:35.579 contactList[3097:a0b] (
"<ContactModel: 0x8d72720>"
)
Clearly, your singleton is successfully adding the ContactModel object to the array of your singleton (as evidenced by your NSLog statement). I assume your question stems from the fact that you're not seeing your file saved.
That's because you're trying to use writeToFile of your NSMutableArray (which tries to save a plist file). If you check the return code of writeToFile, you'll see it failed. This is because you cannot write a plist with an array consisting of custom objects. You might want to use NSKeyedArchiver instead, e.g.:
- (void)saveToFile
{
NSString* path = [[self documentsPath] stringByAppendingPathComponent:#"cList.dat"];
BOOL success = [NSKeyedArchiver archiveRootObject:_cList toFile:path];
NSAssert(success, #"write failed");
}
Anticipating the logical follow-up question, how to read the file, you would use NSKeyedUnarchiver, like so:
-(void)loadFromFile
{
NSString* path = [[self documentsPath] stringByAppendingPathComponent:#"cList.dat"];
self.cList = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
NSAssert(_cList, #"read failed");
}
But, for this to work, you have to make your contact model conform to the NSCoding protocol, namely adding the following methods to that class:
#pragma mark - NSCoding methods
- (NSArray *)propertyNames
{
return #[#"fName", #"lName", #"email", #"phone"];
}
- (id) initWithCoder:(NSCoder *)aDecoder
{
// if `super` conforms to `NSCoding`, then use
//
// self = [super initWithCoder:aDecoder];
//
// in this case, `super` is `NSObject`, so just call `init`
self = [super init];
if (self) {
for (NSString *key in [self propertyNames]) {
[self setValue:[aDecoder decodeObjectForKey:key] forKey:key];
}
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder
{
// if `super` conforms to `NSCoding`, itself, then call `encodeWithCoder` for `super`:
//
// [super encodeWithCoder:aCoder];
//
// in this case, `super` is `NSObject`, so that is not needed
for (NSString *key in [self propertyNames]) {
[aCoder encodeObject:[self valueForKey:key] forKey:key];
}
}
For more information about using archives, see the Archives and Serializations Programming Guide.
So I know my problem is that my transfer array is not being initialized correctly. Where should I put transfer = [[NSMutableArray alloc] init];?
#interface PictureViewController (){
Poi *labelPoi;
}
#end
#implementation PictureViewController
#synthesize imageX;
#synthesize imageY;
#synthesize name;
#synthesize transfer;
- (id)init
{
self = [super init];
if(self) {
transfer = [[NSMutableArray alloc] init];
}
return self;
}
-(id)initWithLabel:(double)imageX andY:(double)imageY withName:(NSString *)name{
self = [super init];
if(self){
// transfer = [[NSMutableArray alloc] init];
self.imageX = imageX;
self.imageY = imageY;
self.name = name;
}
return self;
}
/*-(id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if(self){
transfer = [[NSMutableArray alloc] init];
self.imageX = imageX;
self.imageY = imageY;
self.name = name;
NSLog(#"imageX: %f", self.imageX);
NSLog(#"imageY: %f", imageY);
NSLog(#"name: %#", name);
}
return self;
}*/
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
NSLog(#"transfer count: %lu",(unsigned long)transfer.count);
for(int i = 0; i < transfer.count; i++){
UILabel *label = [[UILabel alloc] initWithFrame: CGRectMake([[transfer objectAtIndex:i] imageLocationX], [[transfer objectAtIndex:i] imageLocationY], 200, 50)];
label.text = [[transfer objectAtIndex:i] name];
label.font = [UIFont systemFontOfSize:14];
label.backgroundColor = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.0];
[self.view addSubview:label];
NSLog(#"asdfasdsd");
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (id)display:(double)imageXX andY:(double)imageYY withName:(NSString *)namee{
NSLog(#"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
NSLog(#"imageX: %f",imageXX);
NSLog(#"imageY: %f", imageYY);
NSLog(#"name: %#", namee);
labelPoi = [[Poi alloc] init];
//transfer = [[NSMutableArray alloc] init];
labelPoi.imageLocationX = imageXX;
labelPoi.imageLocationY = imageYY;
labelPoi.name = namee;
[transfer addObject:labelPoi];
NSLog(#"label.x: %f should be: %f", labelPoi.imageLocationX, imageXX);
NSLog(#"label.y: %f should be: %f", labelPoi.imageLocationY, imageYY);
NSLog(#"label.name: %# should be: %#",labelPoi.name,namee);
NSLog(#"transssssfer: %lu", (unsigned long)transfer.count);
NSLog(#"asfddfsaasfdfdsfsd %f", [[transfer objectAtIndex:0] imageLocationX]);
return self;
}
#end
The Poi object is made up of an imageLocationX, imageLocationY, and name and I am trying to put the Poi object into an array named transfer however, whenever I try to access transfer elements, I receive 0 or null. The (id)display function is being called several times from a different view NSMutable alloc in that function, the array gets reset.
Here is the output:
2013-07-19 11:22:06.736 AR_UAV_App[12466:11303] %%%%%%%%%%%%%%%%%%%%%%%%
2013-07-19 11:22:06.736 AR_UAV_App[12466:11303] imageX: 224.485718
2013-07-19 11:22:06.736 AR_UAV_App[12466:11303] imageY: 116.353401
2013-07-19 11:22:06.736 AR_UAV_App[12466:11303] name: Beutel Student Health Center
2013-07-19 11:22:06.736 AR_UAV_App[12466:11303] label.x: 224.485718 should be: 224.485718
2013-07-19 11:22:06.736 AR_UAV_App[12466:11303] label.y: 116.353401 should be: 116.353401
2013-07-19 11:22:06.736 AR_UAV_App[12466:11303] label.name: Beutel Student Health Center should be: Beutel Student Health Center
2013-07-19 11:22:06.737 AR_UAV_App[12466:11303] transssssfer: 0
2013-07-19 11:22:06.737 AR_UAV_App[12466:11303] asfddfsaasfdfdsfsd 0.000000
2013-07-19 11:22:06.737 AR_UAV_App[12466:11303] #############################################################
EDIT: .h file
#interface PictureViewController : UIViewController{
NSMutableArray *transfer;
}
#property (nonatomic) double imageX;
#property (nonatomic) double imageY;
#property (nonatomic) NSString *name;
#property (nonatomic,retain) NSArray *transfer;
- (IBAction)backView:(id)sender;
- (IBAction)load:(id)sender X:(double)imageX andY:(double)imageY withName:(NSString *)name;
-(id)initWithLabel:(double)imageX andY:(double)imageY withName:(NSString *)name;
-(id)display:(double)imageX andY:(double)imageY withName:(NSString *)name;
#end
This init method should become the "designated" initializer:
-(id)initWithLabel:andY:withName:(NSString *)name
(by the way, it's not named correctly according the naming conventions)
The designated initializer shall initialize the instance properly (that is, in your case it may initialize the array transfer, unless you use a lazy accessor ).
The "designated initializer" is most often the "most specialized" initializer - that is, that one with the most parameters. Most often, there is only one and easily identifiable designated initializer.
The "designated initializer" has the canonical form:
-(id)initWithLabel:(double)imageX andY:(double)imageY withName:(NSString *)name{
self = [super init];
if(self){
// initialization
...
}
}
Other init methods like the init method shall invoke the designated initializer like:
- (id)init {
return [self initWithLabel:0 andY:0 withName:#""];
}
I guess one problem can be that when you are creating this controller you are calling to:
-(id)initWithLabel:(double)imageX andY:(double)imageY withName:(NSString *)name
In case you do that, you are calling to [super init] what will never go through the init method of your class (where you allocated the array). In case you have different methods to init a controller I recommend you to have a:
commonInit{
_transfer = [[NSMutableArray] alloc] init];
}
Then call this method for every init method that you have in your controller so you ensure that array is allocated.
Other thing is just allocate your array in the viewDidLoad of your controller.
Just for making know, you can "allocated" an array without having to take care about release the object by calling to [NSMutableArray arrayWithCapacity:0];
Are you initializing your PictureViewController with -(id)initWithLabel:(double)imageX andY:(double)imageY withName:(NSString *)name? If so, I can tell you what the problem is...
-(id)initWithLabel:(double)imageX andY:(double)imageY withName:(NSString *)name
{
self = [super init]; // <--- You are likely confused about this line
.....
}
[super init] does not pass a message to your custom -(id)init method. It instead is referring to PictureViewController's superclass, which is likely UIViewController.
Your problem should be fixed by uncommenting transfer = [[NSMutableArray alloc] init]; in the initWithLabel: custom init method.
make a property (synthesize it #synthesize transfer=_transfer;), use lazy instantiation like:
-(NSMutableArray*)transfer
{
if (!_transfer)
{
_transfer=[NSMutableArray array];
}
return _transfer;
}
and take it out of your init
UPDATE: Figured out some stuff and changed code.
When I add my NSDictionary to my array it suddenly replaces the previous dictionary I added last time. I don't know why this is happening. I am using a plist as data storage.
I get a error message like this:
Thread 1:Program received signal: "EXC_BAD_ACCESS".
Init
-(id)init{
self=[super init];
if(self){
dbArray = [[NSMutableArray alloc] init];
}
return self;
}
Adding a new item.
-(void)addNewItem:(NSString *)aString
{
// Creates a mutable dictionary with a anonymous string under the NAME key.
NSDictionary *newString = [[NSDictionary alloc] initWithObjectsAndKeys:aString,#"name", nil];
// Adds the new string to empty dbArray.
[dbArray addObject:(newString)];
NSLog(#"[add]:Added anonymous string to dbArray, under name key.");
// Writes the current dbArray (with the dict) to plist and releases retain counts.
[self writeItem];
[newString release];
}
My method to view my data.
-(void)viewData
{
// View data from the created plist file in the Documents directory.
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *finalPath = [documentsDirectory stringByAppendingPathComponent:#"data.plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath:finalPath]) {
self.dbArray = [NSMutableArray arrayWithContentsOfFile:finalPath];
}
else {
self.dbArray = [NSMutableArray array];
}
}
instead this
self.dbArray = [[NSMutableArray alloc] init];
use this
if( nil == self.dbArray ) {
self.dbArray = [[NSMutableArray alloc] init];
}
UPDATE: (based on provided code)
you're using different instances of DataObject class for displaying & saving data. Your content is over-written, because you don't load data from file during initialization of each instance; to fix that fast, you need to implement init method of your DataObject class as below:
- (id)init{
self = [super init];
if(self){
[self viewData];
}
return self;
}
the following code from viewDidLoad of ViewController class will crash your application very often:
db = [[DataObject alloc] init];
[db viewData];
[db release];
array = [[NSMutableArray alloc] initWithArray:[db dbArray]];
replace it with
db = [[DataObject alloc] init];
[db viewData];
array = [[NSMutableArray alloc] initWithArray:[db dbArray]];
call [db release] only in dealloc implementation
another problem, that you'll probably arise - is updated data is not displayed when you're back to the main screen; to fix that add the following method implementation to your ViewController.m file:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[db viewData];
self.array = [NSMutableArray arrayWithArray: db.dbArray];
[self.tableView reloadData];
}
also in AddView.m replace the following code
// Dismiss view and reload tableview.
ViewController *vc = [[ViewController alloc] init];
[self dismissModalViewControllerAnimated:YES];
[vc release];
with
// Dismiss view and reload tableview.
[self dismissModalViewControllerAnimated:YES];
Just as advise: see more information about using delegates and passing object instances & copies between objects.
I think you are creating a new Array:
self.dbArray = [[NSMutableArray alloc] init];
You should create the dbArray on the viewDidLoad or on the init of your UIViewController (I am assuming you are using this on an UIViewController)
inside your DataObject do the following:
-(id)init{
self=[super init];
if(self){
self.dbArray = [[NSMutableArray alloc] init];
}
return self;
}