I have a UITableView populated by a feed from searchtwitter.com. I also have a details table with an image and UILabel. I have all this working, but I want to add a UIButton on the detail page that will save the UIImage and the label into a property list. I'm very new to this; here is what I have so far (not working).
- (IBAction)SaveFriend:(id)sender
{
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory = [path objectAtIndex:0];
NSString *plistPath = [documentDirectory stringByAppendingPathComponent:#"TwitterFriends.plist"];
NSDictionary * tweet = [[NSDictionary alloc]init];
NSString *text = [tweet objectForKey:#"from_user"];
NSString *user = [tweet objectForKey:#"from_user_name"];
personName.text = text;
personInfo.text = user;
// create dictionary with values in UITextFields
NSDictionary *plistDict = [NSDictionary dictionaryWithObjects: [NSArray arrayWithObjects: personName, personInfo, nil] forKeys:[NSArray arrayWithObjects: #"Name", #"info", nil]];
NSString *error = nil;
// create NSData from dictionary
NSData *plistData = [NSPropertyListSerialization dataFromPropertyList:plistDict format:NSPropertyListXMLFormat_v1_0 errorDescription:&error];
// check is plistData exists
if(plistData)
{
// write plistData to our Data.plist file
[tweet writeToFile:plistPath atomically:YES];
}
else
{
NSLog(#"Error in saveData: %#", error);
[error release];
}
}
Instead of using a .plist, try using an NSArray or NSMutableArray and then the writeToFile method. For example:
NSMutableArray *temp = [NSMutableArray new];
[temp addObject:image];
[temp addObject:label];
[temp writeToFile:[self saveFilePath:#"filename"] atomically:YES];
//Returns the saved information path
- (NSString*) saveFilePath: (NSString *) add
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
NSString *path = [paths objectAtIndex:0];
NSString *filename = [path stringByAppendingPathComponent:add];
return filename;
}
Related
I have created a simple plist file with some user preferences for a card game I'm writing.
I have also created a controller that reads and writes to this plist file which is a singelton.
everything works fine, but then after a couple of tries it stops working.
Logging the values to the console it shows the list returning a value of 0 which causes my app to crash
I have deleted the plist and created a new one and then the same story, works fine for 2 or three time and then boom zero.
here is a copy of the controller singelton code:
#implementation userOptionsController
static userOptionsController* _sharedOptionsController = nil;
#synthesize backgroundSound=_backgroundSound;
#synthesize soundEffects = _soundEffects;
#synthesize coach = _coach;
#synthesize numberOfDecks = _numberOfDecks ;
+(userOptionsController*)sharedOptionsController{
#synchronized([userOptionsController class])
{
if(!_sharedOptionsController)
[[self alloc]init];
return _sharedOptionsController;
}
return nil;
}
+(id)alloc
{
#synchronized ([userOptionsController class])
{
NSAssert(_sharedOptionsController == nil, #"Attempted to allocate a second instance of userOptionsController singleton");
_sharedOptionsController = [super alloc];
return _sharedOptionsController;
}
return nil;
}
- (id) init {
self = [super init];
if (self) {
}
return self;
}
-(void)readPlistFile
{
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"playerPrefOptions.plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath: path])
{
NSString *bundle = [[NSBundle mainBundle] pathForResource:#"playerPrefOptions" ofType:#"plist"];
[fileManager copyItemAtPath:bundle toPath: path error:&error];
}
NSMutableDictionary *temp = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
self.backgroundSound = [[temp objectForKey:#"backgroundSounds"]boolValue];
self.soundEffects = [[temp objectForKey:#"soundEffects"]boolValue];
self.coach =[[temp objectForKey:#"coach"]boolValue];
self.numberOfDecks = [[temp objectForKey:#"numberOfDecks"]intValue];
}
-(void)writeOptionsToFile
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"playerPrefOptions.plist"];
NSMutableDictionary *infoDict = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
NSNumber *moshe = [NSNumber numberWithInt:self.numberOfDecks];
[infoDict setObject: moshe forKey:#"numberOfDecks"];
[infoDict setObject:[NSNumber numberWithBool:self.coach] forKey:#"coach"];
[infoDict setObject:[NSNumber numberWithBool:self.backgroundSound] forKey:#"backgroundSounds"];
[infoDict setObject:[NSNumber numberWithBool:self.soundEffects] forKey:#"soundEffects"];
[infoDict writeToFile:path atomically:YES];
}
#end
so the property :
int numberOfDecks =[userOptionsController sharedOptionsController].numberOfDecks;
will return zero.
any ideas?
thanks.
Rather than use a plist for this content, it looks like NSUserDefaults is a more appropriate location.
Instead of shipping the app with a default plist file, instead just registerDefaults: with NSUserDefaults (often done in your app delegate application:didFinishLaunchingWithOptions:).
Then, whenever any changes are made just update NSUserDefaults and call synchronize to save the changes.
Try this and see what it does (what logs are output):
#implementation userOptionsController
+ (userOptionsController*)sharedOptionsController
{
static dispatch_once_t pred = 0;
__strong static id _sharedObject = nil;
dispatch_once(&pred, ^{
_sharedObject = [[self alloc] init];
});
return _sharedObject;
}
- (id) init {
self = [super init];
if (self) {
}
return self;
}
-(void)readPlistFile
{
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"playerPrefOptions.plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath: path])
{
NSString *bundle = [[NSBundle mainBundle] pathForResource:#"playerPrefOptions" ofType:#"plist"];
if (![fileManager copyItemAtPath:bundle toPath: path error:&error]) {
NSLog(#"ERROR - file couldn't be copied: %#", error);
}
}
NSMutableDictionary *temp = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
if (temp == nil) {
NSLog(#"ERROR - file couldn't be read");
}
self.backgroundSound = [[temp objectForKey:#"backgroundSounds"]boolValue];
self.soundEffects = [[temp objectForKey:#"soundEffects"]boolValue];
self.coach =[[temp objectForKey:#"coach"]boolValue];
self.numberOfDecks = [[temp objectForKey:#"numberOfDecks"]intValue];
}
-(void)writeOptionsToFile
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"playerPrefOptions.plist"];
NSMutableDictionary *infoDict = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
NSNumber *moshe = [NSNumber numberWithInt:self.numberOfDecks];
[infoDict setObject: moshe forKey:#"numberOfDecks"];
[infoDict setObject:[NSNumber numberWithBool:self.coach] forKey:#"coach"];
[infoDict setObject:[NSNumber numberWithBool:self.backgroundSound] forKey:#"backgroundSounds"];
[infoDict setObject:[NSNumber numberWithBool:self.soundEffects] forKey:#"soundEffects"];
if (![infoDict writeToFile:path atomically:YES]) {
NSLog(#"ERROR - failed to write the new file (%#)", path);
} else {
NSLog(#"Completed write of:\n%#", infoDict);
}
}
#end
I can't save my new data to plist file for some reason. This is code I have been using for saving data:
-(void)saveData:(NSMutableDictionary *)dictionaryData toFile:(NSString *)filename {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDir = [paths objectAtIndex:0];
NSString *path = [docDir stringByAppendingPathComponent:filename];
NSMutableArray *data = [[NSMutableArray alloc] initWithContentsOfFile:path];
[data addObject:dictionaryData];
[data writeToFile:filename atomically:YES];
}
this is code I used to copy file from bundle to app directory in case if it is not there :
-(NSMutableArray *)loadFromFile:(NSString *)filename {
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDir = [paths objectAtIndex:0];
NSString *path = [docDir stringByAppendingPathComponent:filename];
NSFileManager *fileMgr = [NSFileManager defaultManager];
if(![fileMgr fileExistsAtPath:path]) {
NSArray *fileArray = [filename componentsSeparatedByString:#"."];
NSString *name = [fileArray objectAtIndex:0];
NSString *ext = [fileArray objectAtIndex:1];
NSString *bundle = [[NSBundle mainBundle] pathForResource:name ofType:ext];
[fileMgr copyItemAtPath:bundle toPath:path error:&error];
}
NSMutableArray *data = [[NSMutableArray alloc] initWithContentsOfFile:path];
return data;
}
For some reason I can't save new data to plist file. When I try to add new NSMutableDictionary object to my plist file (with saveData:toFile: method) and than reload my array variable with the plist file data - new object is not there. Am I doing something wrong?
this is how I load plist file :
#property (nonatomic, strong) NSMutableArray *modules;
#property (nonatomic, strong) NSMutableDictionary *module;
- (void)viewDidLoad {
[super viewDidLoad];
self.modules = [self loadFromFile:#"ModulesList.plist"];
self.module = [self.modules objectAtIndex:0];
for (int i = 0; i < self.modules.count; i++ ) {
NSLog(#"Modules array from plist file, module at index %i : %#",i, [self.modules objectAtIndex:i]);
}
than for testing purpose I have this code to add new module object:
- (IBAction)leftButton:(id)sender {
NSString *mytitle = [[NSString alloc] initWithFormat:#"my title"];
NSString *myauthor = [[NSString alloc] initWithFormat:#"my author2"];
NSUInteger myean = 22023423;
NSString *mytitle2 = [[NSString alloc] initWithFormat:#"my title 2"];
NSString *myauthor2 = [[NSString alloc] initWithFormat:#"my author2"];
NSUInteger myean2 = 29032432;
NSString *mytitle3 = [[NSString alloc] initWithFormat:#"my title 3"];
NSString *myauthor3 = [[NSString alloc] initWithFormat:#"my author 3"];
NSUInteger myean3 = 21023423;
NSMutableDictionary *mybook = [[NSMutableDictionary alloc] init];
NSMutableDictionary *mybook2 = [[NSMutableDictionary alloc] init];
NSMutableDictionary *mybook3 = [[NSMutableDictionary alloc] init];
[mybook setObject:mytitle forKey:#"title"];
[mybook setObject:myauthor forKey:#"author"];
[mybook setObject:[NSNumber numberWithInteger:myean] forKey:#"ean"];
[mybook2 setObject:mytitle2 forKey:#"title"];
[mybook2 setObject:myauthor2 forKey:#"author"];
[mybook2 setObject:[NSNumber numberWithInteger:myean2] forKey:#"ean"];
[mybook3 setObject:mytitle3 forKey:#"title"];
[mybook3 setObject:myauthor3 forKey:#"author"];
[mybook3 setObject:[NSNumber numberWithInteger:myean3] forKey:#"ean"];
NSMutableArray *mybooks = [[NSMutableArray alloc] init];
[mybooks addObject:mybook];
[mybooks addObject:mybook2];
[mybooks addObject:mybook3];
[self.module setObject:mybooks forKey:#"books"];
[self.modules addObject:self.module];
for (int i = 0; i < self.modules.count; i++ ) {
NSLog(#"Modules array after add operation, module at index: %i: %#",i, [self.modules objectAtIndex:i]);
}
[self saveData:self.module toFile:#"ModulesList.plist"];
}
than when I will reload my self.modules array from plist with button action, my new data is not there:
- (IBAction)reload:(id)sender {
self.modules = [self loadFromFile:#"ModulesList.plist"];
for (int i = 0; i < self.modules.count; i++ ) {
NSLog(#"RELOAD: Modules array from plist file, module at index %i : %#",i,[self.modules objectAtIndex:i]);
}
}
this is screenshot of my plist file : http://dl.dropbox.com/u/49076351/Screen%20Shot%202013-02-27%20at%2016.27.45.png
Hello I am trying to load data from a file
This function save the data to a file in documents folder
- (IBAction)saveUser:(id)sender{
NSString *name = [nameField stringValue];
NSString *weight = [weightField stringValue];
NSDate *date = [datePick dateValue];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setValue:[nameField stringValue] forKey:#"name"];
[dict setValue:[weightField stringValue] forKey:#"weight"];
[dict setValue:date forKey:#"date"];
[dict writeToFile:name atomically:YES];
}
However when I try to load the file and get the data from it I cant, could someone tell me how this is done done.
Edit to show loadFunction
-(IBAction)loadUser:(id)sender{
NSString *weight = [weightField stringValue];
NSDate *date = [datePick dateValue];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *loadPath = [documentsDirectory stringByAppendingPathComponent:name];
NSMutableDictionary *savedData = [[NSMutableDictionary alloc] initWithContentsOfFile: name];
NSLog(#"%#", weight);
}
To fix your answer. here is a code that works, you pretty much did not give a filename.
NSString *filename = [documentsDirectory stringByAppendingPathComponent:#"file.txt"];
And in your line where you write the file :
[dict writeToFile:name atomically:YES];
you must change name to filename, like this
[dict writeToFile:filename atomically:YES];
And in your load data method :
NSString *filename = [documentsDirectory stringByAppendingPathComponent:#"file.txt"];
NSMutableDictionary *savedData = [[NSMutableDictionary alloc] initWithContentsOfFile:filename];
NSLog(#"The weight is : %#", [savedData valueForKey:#"weight"]);
The following seems to do what you intend (minus the UI element dependencies in your code):
#import <Foundation/Foundation.h>
static NSString *pathToDocuments(void) {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
return [paths objectAtIndex:0];
}
int main(int argc, char *argv[]) {
NSAutoreleasePool *p = [[NSAutoreleasePool alloc] init];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setValue:#"SomeName" forKey:#"name"];
[dict setValue:#"SomeWeight" forKey:#"weight"];
[dict setValue:[NSDate date] forKey:#"date"];
NSString *filePath = [pathToDocuments() stringByAppendingPathComponent:[dict objectForKey:#"name"]];
[dict writeToFile:filePath atomically:YES];
[dict release]; dict = nil;
NSLog(#"%s - Confirming dict is nil: %#",__FUNCTION__,dict);
dict = [[NSDictionary dictionaryWithContentsOfFile:filePath] mutableCopy];
NSLog(#"%s - weight = %#",__FUNCTION__,[dict objectForKey:#"weight"] );
[p release];
}
This prints the following to the console:
2012-10-19 06:40:38.691 Untitled[10633:707] main - Confirming dict is nil: (null)
2012-10-19 06:40:38.693 Untitled[10633:707] main - weight = SomeWeight
EDIT:
That said, I think the problem may be the file path in loadUser...
With the following way...
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString* path = [documentsDirectory stringByAppendingPathComponent:
[NSString stringWithFormat:#"/lkj/"]];
NSString *fileName = [NSString stringWithFormat:#"/sandbox/2012_05_11.json"];
[[self restClient] loadFile:fileName intoPath:path];
NSString *fileContent = [[NSString alloc] initWithContentsOfFile:path];
SBJsonParser *parser = [[SBJsonParser alloc] init];
NSDictionary *data = (NSDictionary *) [parser objectWithString:fileContent error:nil];
// getting the data from inside of "menu"
NSString *message = (NSString *) [data objectForKey:#"message"];
NSString *name = (NSString *) [data objectForKey:#"name"];
namegroup.text = [NSString stringWithFormat:#"%# %#",name, message];
...I am trying to parse a document I have previously made with other code...
{"message":["Untitled1a","Untitled2a","Untitled3a"],"name":["Untitled1b","Untitled2b","Untitled3b"]}
with the code above though, in name group.text, this appears...
(untitled, untitled, untitled) (untitled, untitled, untitled)
...but what I would like to do is to allocate many UITextFields, each of them in pairs, (2, 2, 2..), one field which displays the name and the other the message, so pair up 1a with 1b, 2a with 2b... obviously the fields won't be Untitled1a, but "how are you"...
But I can't seem to fix this issue!! Please help!!
You may try something like this:
NSArray *message = [data objectForKey:#"message"];
NSArray *name = [data objectForKey:#"name"];
NSDictionary* Dictionary = [NSDictionary dictionaryWithObjects:message forKeys:name];
for (NSString* Key in [Dictionary allKeys]){
NSLog(#"%# %#",Key,[Dictionary objectForKey:Key]);
}
Currently i'm using these codes to save my images into NSDocumentDirectory. I use this counter as the naming convention for them.
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)selectedImage editingInfo:(NSDictionary *)editingInfo
{
[self.popoverController dismissPopoverAnimated:YES];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
NSString *savedImagePath = [documentsDir stringByAppendingPathComponent:[NSString stringWithFormat:#"%d.png", counter]];
UIImage *image = imageView.image;
NSData *imageData = UIImagePNGRepresentation(image);
[imageData writeToFile:savedImagePath atomically:NO];
}
I use this method because it's easier for me to retrieve all of them by using a loop. I want to retrieve all the images from the NSDocumentDirectory so that i can display them in another view. The following codes show how i retrieve them.
-(NSMutableArray *)GetImage:(NSMutableArray *)arrayImgNames
{
NSMutableArray *tempArray;
for(int i=0;i<[arrayImgNames count]; i++)
{
NSArray *paths1 = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths1 objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent: [arrayImgNames objectAtIndex:i]];
[tempArray addObject:[[UIImage alloc] initWithContentsOfFile:filePath]];
return tempArray;
}
}
However, i do not wish to use the counter as a naming convention for my images. I want to use proper names for them but if i do so, i will have to change my method of retrieving all the images.
Is there any other way that i can retrieve all images other than this method i mentioned?
You can retrieve files using next approach:
NSURL *url = [[AppDelegate sharedAppDelegate] applicationDocumentsDirectory];
NSError *error = nil;
NSArray *properties = [NSArray arrayWithObjects: NSURLLocalizedNameKey, NSURLLocalizedTypeDescriptionKey, nil];
NSArray *files = [[NSFileManager defaultManager] contentsOfDirectoryAtURL:url
includingPropertiesForKeys:properties options:(NSDirectoryEnumerationSkipsPackageDescendants)
error:&error];
In files paths to all files of documents directory will be stored. Next code will help you to get there names:
NSURL *url = [files objectAtIndex:index];
NSString *localizedName = [url lastPathComponent];