I'm making my slot machine app using iCarousel, my iCarousel contains images from NSDocumentDirectory this images was from my ImagePicker. So here's how my app works, when the user press a button the iCarousel spins.
When it stops, display the item for 3 seconds, then deletes it.
My problem is when I go to another View, the deleted index/item is there again. How to maintain my array even I go to different views. That the deleted index/item will not be shown, only until the app was restarted, like saving an array. Thanks for the help.
// my array
- (void)viewDidLoad
{
self.images = [NSMutableArray new];
for(int i = 0; i <= 100; i++)
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
NSString *savedImagePath = [documentsDir stringByAppendingPathComponent:[NSString stringWithFormat:#"images%d.png", i]];
if([[NSFileManager defaultManager] fileExistsAtPath:savedImagePath]){
[images addObject:[UIImage imageWithContentsOfFile:savedImagePath]];
}
}
}
- (void)viewWillAppear:(BOOL)animated {
spinButton = [UIButton buttonWithType:UIButtonTypeCustom];
[spinButton addTarget:self action:#selector(spin) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:spinButton];
}
- (void) carouselDidEndScrollingAnimation:(iCarousel *)carousel{
[NSTimer scheduledTimerWithTimeInterval:0.56 //this arranges the duration of the scroll
target:self
selector:#selector(deleteItem)
userInfo:nil
repeats:NO];
}
// spin and delete method
- (void)spin {
[carousel scrollByNumberOfItems:-35 duration:10.7550f];
}
-(void) deleteItem {
//Removes the object chosen
NSInteger index = carousel.currentItemIndex;
[carousel removeItemAtIndex:index animated:YES];
[images removeObjectAtIndex:index];
}
What I need is, when the index/item is deleted, it will not be shown temporarily even if I go to other views. The views will only be restarted after app is closed and open again
Your problem is your are creating the images NSMutableArray every time you enter the view.
As #Saleh said you should place the array outside your view controller. To do it in the appDelegate, like he was suggesting, do the following:
In AppDelegate.h declare:
#property( strong, nonatomic) NSMutableArray *images;
In AppDelegate.m:
#synthesize images;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Read the images after the existing code ....
self.images = [NSMutableArray array];
for(int i = 0; i <= 100; i++)
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
NSString *savedImagePath = [documentsDir stringByAppendingPathComponent:[NSString stringWithFormat:#"images%d.png", i]];
if([[NSFileManager defaultManager] fileExistsAtPath:savedImagePath]){
[images addObject:[UIImage imageWithContentsOfFile:savedImagePath]];
}
}
return YES;
}
Then in your ViewController.m:
#import "AppDelegate.h"
and change your viewDidLoad method:
- (void)viewDidLoad
{
[super viewDidLoad];
self.images = ((AppDelegate *)[[UIApplication sharedApplication] delegate]).images;
}
This should work.
Use one instance of the array, you are initializing it only once. Put the array in appDelegate which will make it singelton for the whole app.
Related
I created an NSMutableDictionary called *temp in my .h file of the main viewController, and added this code to bring in the information from my .plist file.
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *path = [[NSBundle mainBundle] pathForResource:#"Data" ofType:#"plist"];
temp=[NSMutableDictionary dictionaryWithContentsOfFile:path];
}
In the same view controller, I added a button action and added the following code:
-(IBAction)mathButton:(UIButton *)_sender
{
label1.text = [temp objectForKey:#"m1name"];
}
Where "label1 is a text field in the .xib, and m1name is one of the keys in the .plist
But when I run it, it doesn't work, and highlights label1.text = [temp objectForKey:#"m1name"]; and calls it bad access.
I've been stuck on this for a couple of days, and tried lots of things. An answer would be really helpful.
Thanks
temp=[NSMutableDictionary dictionaryWithContentsOfFile:path];
You're not retaining the dictionary created via dictionaryWithContentsOfFile:path. You should either change that line to:
temp = [[NSMutableDictionary dictionaryWithContentsOfFile:path] retain];
(and make sure it's released in dealloc), or, if temp is a property, set it via
self.temp = [NSMutableDictionary dictionaryWithContentsOfFile:path];
In .h:
#interface ...
{
NSMutableDictionary* temp;
}
In .m:
- (void)viewDidLoad
{
[super viewDidLoad];
NSString* path = [[NSBundle mainBundle] pathForResource: #"Data"
ofType: #"plist"];
BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath: path];
if (exists)
{
temp = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
NSLog(#"%#", [temp description]);
}
}
- (IBAction) mathButton: (UIButton *)_sender
{
label1.text = [temp objectForKey: #"m1name"];
}
If MRC:
- (void) dealloc
{
[temp release];
[super dealloc];
}
I've got a search page at the moment which will load a list of results for a web-service, but when I return to the search page I would like to 'save' whatever was entered (e.g. 'resto italian') and then display that entry and previous entries into a table view below, like in my following image:
My plan was to use property list serialization - if there isn't already a list, create a property list called history.plist, and populate it with each search term that is made, and display the nearest ten in the table view like above.
What I've tried:
// should create history.plist
- (NSString *)dataFilePath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
return [documentsDirectory stringByAppendingString:#"history.plist"];
}
/* This is the action for when 'search' is clicked - calls the method above to create
a new plist if it's not already created.
I then try to display the contents of the of the file in the textfield itself
(for testing purposes) but it's not saving/displaying properly at the moment. */
- (IBAction)saveHistory:(id)sender {
NSString *filePath = [self dataFilePath];
if([[NSFileManager defaultManager] fileExistsAtPath:filePath])
{
NSArray *array = [[NSArray alloc] initWithContentsOfFile:filePath];
for (int i = 0; i < (sizeof(array)); i++) {
UITextField *theField = self.searchHistory;
theField.text = [NSString stringWithFormat:#"%#", array];
}
}
UIApplication *app = [UIApplication sharedApplication];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(applicationWillResignActive:) name:UIApplicationWillResignActiveNotification object:app];
}
Any links to tutorials attempting to do this, suggestions towards what I should do, or improvements to what I have would be greatly appreciated.
This should fix the problem:
// This is inside viewDidLoad
UIApplication *myApp = [UIApplication sharedApplication];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(applicationDidEnterBackground:)
name:UIApplicationDidEnterBackgroundNotification
object:myApp];
// This is inside my table view - where I'm loading the file data to display in table cells
NSString *myPath = [self dataFilePath];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:myPath];
if (fileExists) {
NSArray *values = [[NSArray alloc] initWithContentsOfFile:myPath];
for (int i = 0; i < values.count; i++) {
cell.historyDisplay.text = [NSString stringWithFormat:#"%#", [values objectAtIndex:i]];
}
}
// This is the file path for history.plist
- (NSString *)dataFilePath {
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
return [[path objectAtIndex:0] stringByAppendingString:#"history.plist"];
}
// This is my search button - I want to save whatever was typed in the text field, into history.plist, to display in my tableview whenever a user goes to it.
- (IBAction)saveHistory:(id)sender {
NSMutableArray *values = [[NSMutableArray alloc]initWithContentsOfFile:[self dataFilePath]];
if(searchInputTextField.text.length > 0)
[values addObject:searchInputTextField.text];
[values writeToFile:[self dataFilePath] atomically:YES];
[leTableView reloadData];
}
I would use my suggest in comments, but here's some edits to your code that might help in the meantime.
NSArray *array = [[NSArray alloc] initWithContentsOfFile:filePath];
for (int i = 0; i <array.count; i++) {
//I don't know what this line means
UITextField *theField = self.searchHistory;
//Change this line to this
theField.text = [NSString stringWithFormat:#"%#", [array objectAtIndex:i]];
}
I would use Core Data, creating a class, i.e. HistoryRecord with attributes termSearched and timestamp of type NSString and NSDate respectively.
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#interface HistoryRecordManagedObject : NSManagedObject
#property (nonatomic, retain) NSString *termSearched;
#property (nonatomic, retain) NSDate *timestamp;
+ (NSArray *)findEntity:(NSString *)entity withPredicate:(NSPredicate *)predicate
#end
Implementation
#import "HistoryRecordManagedObject.h"
#implementation HistoryRecordManagedObject
#dynamic termSearched;
#dynamic timstamp;
+ (NSArray *)findEntity:(NSString *)entity withPredicate:(NSPredicate *)predicate
{
NSError *error;
NSArray *fetchedObjects;
/* After set all properties, executes fetch request */
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entityDesc = [NSEntityDescription entityForName:entity
inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entityDesc];
[fetchRequest setPredicate:predicate];
fetchedObjects = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
[fetchRequest release];
return fetchedObjects;
}
#end
Of course that's not just this! There are some extra stuff that must be done to use Core Data such as create the model. Read a little about it! It's worth!
Good luck!
In the action for searching, just save the search result to NSUserDefaults.
NSMutableArray *searches = [[NSUserDefaults standardUserDefaults] arrayForKey:#"searches"];
[searches insertObject:textField.text atIndex:0];
[[NSUserDefaults standardUserDefaults] setObject:searches forKey:#"searches"];
[[NSUserDefaults standardUserDefaults] synchronize];
Then load the same array for the tables data source and reload the table in viewwillappear and when keyboard is dismissed.
Replace your saveHistory function by below way:
- (IBAction)saveHistory:(id)sender
{
NSMutableArray *values = [[NSMutableArray alloc]initWithContentsOfFile:[self dataFilePath]];
if(searchInputTextField.text.length > 0)
[values addObject:searchInputTextField.text];
[values writeToFile:[self dataFilePath] atomically:YES];
[leTableView reloadData];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return values.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
}
cell.textLabel.text = [values objectAtIndex:indexPath.row];
}
Hello there I'm trying to create a dictionary with with phone numbers and I can populate the dictionary and add it to a plist but when I try to add to the plist again I overwrite the file.
#import "FirstViewController.h"
#interface FirstViewController ()
{
NSMutableDictionary *NameNumberDict;
NSDictionary *plistDict;
NSMutableArray *numberArray;
NSString *filePath;
}
#end
#implementation FirstViewController
#synthesize NameTxtField;
#synthesize FirstNumField;
#synthesize SecNumField;
#synthesize personName;
#synthesize phoneNumbers;
- (void)viewDidLoad
{
[super viewDidLoad];
//get some memory
plistDict = [[NSDictionary alloc]init];
NameNumberDict = [[NSMutableDictionary alloc]init];
//make a file path string
NSArray *pathArray = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [pathArray objectAtIndex:0];
filePath = [path stringByAppendingPathComponent:#"data.plist"];
NSFileManager *manager = [NSFileManager defaultManager];
// here i set the Dictionary to the file
//give the file to my dictonary
NameNumberDict = [[NSMutableDictionary alloc] initWithContentsOfFile:filePath];
NSLog(#"The count: %i", [NameNumberDict count]);
//make sure the file is there
NSString *err = nil;
NSData *plist;
plist = [NSPropertyListSerialization dataFromPropertyList:NameNumberDict format:NSPropertyListBinaryFormat_v1_0 errorDescription:&err];
if([manager fileExistsAtPath:#"data.plist"] == NO)
{
[manager createFileAtPath:[NSString stringWithFormat:#"data.plist"] contents:plist attributes:nil];
}
}
- (void)viewDidUnload
{
[self setNameTxtField:nil];
[self setFirstNumField:nil];
[self setSecNumField:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
// Populate the dictionary when they dismiss the keyboard if all the data is filled out
-(IBAction)TextFieldReturn:(id)TextField
{
if(!NameTxtField.text && !FirstNumField.text && !SecNumField.text);
{
NSString *name = NameTxtField.text;
numberArray = [[NSMutableArray alloc]init];
[numberArray addObject:FirstNumField.text];
[numberArray addObject:SecNumField.text];
[NameNumberDict setObject:name forKey:#"Name"];
[NameNumberDict setObject:numberArray forKey:#"Number"];
NSLog(#"dicSave: %#",NameNumberDict);
}
[TextField resignFirstResponder];
}
// and down here is where im lost Im not sure how to append the data to the Dictionary and write it to file
- (IBAction)AddBtn:(UIButton *)sender
{
plistDict = [[NSMutableDictionary alloc]initWithDictionary:NameNumberDict];
[plistDict writeToFile:filePath atomically:YES];
NSLog (#"File %# exists on iPhone",filePath);
}
#end
In your "TextFieldReturn" method, I see you're always resetting the "Name" and "Number" objects of your "NameNumberDict" mutable dictionary each time it's being called.
I think what you really want to do is add a new dictionary (for each new name & number) to a mutable array and then write that mutable array out to a file (which would end up being your property list file).
Also, just as a style note: Method names and variable names should always start with a lowercase letter (e.g. "textFieldReturn", "addBtn", "nameNumberDict", etc.) while class names (e.g. "FirstViewController") are what start capitalized.
I have the following code called with NSNotification center, i know its being called because the array is appearing in the NSLog, but my label chipCount is not updating with the new value. Is there perhaps a method I applied wrong when extracting the string from the array?
-(NSString *) dataFilePath {
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory = [path objectAtIndex:0];
return [documentDirectory stringByAppendingPathComponent:#"Chips.plist"];
}
-(void)readPlist {
[self dataFilePath];
NSString *filePath = [self dataFilePath];
if([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
chipArray = [[NSArray alloc] initWithContentsOfFile:filePath];
NSLog(#"%#\n", chipArray);
NSLog(#"%#\n", filePath);
NSString *chipcountString = [chipArray objectAtIndex:0];
chipsFloat = [chipcountString intValue];
chipCount.text = [NSString stringWithFormat:#"%i", chipsFloat];
//[arrayForPlist release];
}
}
I think this is a multithread problem. Update UI must in the main thread. Maybe readPlist is
executed in another thread.
Try this code below, maybe it can help you:
[self performSelectorOnMainThread:#selector(theProcess:) withObject:nil waitUntilDone:YES];
- (void) theProcess:(id)sender
{
....
chipCount.text = [NSString stringWithFormat:#"%i", chipsFloat];
}
Assusming that chipcount is a UILabel.. is it possible that you need to tell it to refresh the label?
[chipcount setNeedsDisplay];
Just an idea.
I'm making an app where I need to save the text in multiple views in the app when the app quits. I also need to be able to remove all of the data from just one of those views and when the app quits, it's possible not all of those views will have been created yet.
After reading this post I thought perhaps it would be good to use a singleton that manages my app data which loads in the data when it is first requested and saved it when the app quits. Then in each view where I need to save data I can just set it on the singleton.
I gave it a go but have run into some issues. At first I didn't synthesize the properties (as in the post I was using as a guide) but the compiler told me I needed to make getters and setters, so I did. Now when my applicationWIllTerminate: gets call the app crashes and the console says "Program received signal: “EXC_BAD_ACCESS”. kill quit".
Is anyone able to tell me what I'm doing wrong, or suggest a better approach to saving the data?
//SavedData.h
#import <Foundation/Foundation.h>
#define kFileName #"appData.plist"
#interface SavedData : NSObject {
NSString *information;
NSString *name;
NSString *email;
NSString *phone;
NSString *mobile;
}
#property(assign) NSString *information;
#property(assign) NSString *name;
#property(assign) NSString *email;
#property(assign) NSString *phone;
#property(assign) NSString *mobile;
+ (SavedData *)singleton;
+ (NSString *)dataFilePath;
+ (void)applicationWillTerminate:(NSNotification *)notification;
#end
//SavedData.m
#import "SavedData.h"
#implementation SavedData
#synthesize information;
#synthesize name;
#synthesize email;
#synthesize phone;
#synthesize mobile;
static SavedData * SavedData_Singleton = nil;
+ (SavedData *)singleton{
if (nil == SavedData_Singleton){
SavedData_Singleton = [[SavedData_Singleton alloc] init];
NSString *filePath = [self dataFilePath];
if([[NSFileManager defaultManager] fileExistsAtPath:filePath]){
NSMutableArray * array = [[NSMutableArray alloc] initWithContentsOfFile:filePath];
information = [array objectAtIndex:0];
name = [array objectAtIndex:1];
email = [array objectAtIndex:2];
phone = [array objectAtIndex:3];
mobile = [array objectAtIndex:4];
[array release];
}
UIApplication *app = [UIApplication sharedApplication];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(applicationWillTerminate:) name:UIApplicationWillTerminateNotification object:app];
}
return SavedData_Singleton;
}
+ (NSString *)dataFilePath{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *DocumentsDirectory = [paths objectAtIndex:0];
return [DocumentsDirectory stringByAppendingPathComponent:kFileName];
}
+ (void)applicationWillTerminate:(NSNotification *)notification{
NSLog(#"Application will terminate received");
NSMutableArray *array = [[NSMutableArray alloc] init];
[array addObject:information];
[array addObject:name];
[array addObject:email];
[array addObject:phone];
[array addObject:mobile];
[array writeToFile:[self dataFilePath] atomically:YES];
[array release];
}
#end
Then when I want to use it I do
myLabel.text = [SavedData singleton].information;
And when I change the field
[SavedData singleton].information = #"my string";
Any help will be very much appreciated!
You might want to change your properties to be (retain) instead of assign.
You might want to get the singleton header file I use. It is quite nice for me.
What is likely happening is that you load up your array from a file, and assign it to the property. But it is being autoreleased, and thus it doesn't exist anymore. So when you try to access the memory later, it crashes.
Further reading on memory management: http://www.cocoadev.com/index.pl?MemoryManagement