In my app I am downloading images from url and saving into application documents directory. Now I want to show these downloaded images as image gallery. For image gallery I am using fGallery, I am able to configure it and successfully pushed it on navigation controller and fGallery view is also visible but its not showing my images, I provide fGalley with images array like this
Header File
#interface myController <FGalleryViewControllerDelegate>
#property (strong, nonatomic) FGalleryViewController *localGallery;
#property (strong, nonatomic) NSMutableArray *localImages;
Class File
//These are delegate methods of FGalleryViewControllerDelegate
- (NSString*)photoGallery:(FGalleryViewController*)gallery filePathForPhotoSize:(FGalleryPhotoSize)size atIndex:(NSUInteger)index
{
return [localImages objectAtIndex:index];
}
- (NSString*)photoGallery:(FGalleryViewController *)gallery urlForPhotoSize:(FGalleryPhotoSize)size atIndex:(NSUInteger)index
{
return [localImages objectAtIndex:index];
}
- (int)numberOfPhotosForPhotoGallery:(FGalleryViewController *)gallery
{
int num;
num = [localImages count];
return num;
}
- (FGalleryPhotoSourceType)photoGallery:(FGalleryViewController *)gallery sourceTypeForPhotoAtIndex:(NSUInteger)index
{
return FGalleryPhotoSourceTypeLocal;
}
//Delegate method ends here
// My method to show gallery with my images
-(void)ShowGallery
{
localImages = [[NSMutableArray alloc]init];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
NSString *dataPath = [documentsDir stringByAppendingPathComponent:chatWithUser;
NSString *msgsColumn;
//database query to fetch all images name and then
while([results next])
{
msgsColumn = [results stringForColumn:#"msgs"];
if([[[msgsColumn componentsSeparatedByString:#"."]objectAtIndex:1]isEqualToString:#"jpg"])
{
[localImages addObject:[dataPath stringByAppendingPathComponent:msgsColumn]];
}
}
[database close];
localGallery = [[FGalleryViewController alloc]initWithPhotoSource:self];
[self.navigationController pushViewController:localGallery animated:YES];
}
For images path i used stringByAppendingPathComponent but I also tried stringByAppendingString to guide that images resides in documents directory but nothing is working.
Please assist me to figure out what is going wrong.
I found the solution, and here it is
https://github.com/gdavis/FGallery-iPhone/issues/15
Related
I am very new to creating applications and haven't fully figured out how to use the plist function within XCode.
My problem is that I have 3 different input methods within a view controller to which the user will select values from, those being a stepper, a picker view and a date that logs the current date, which I would like to save to a plist so that the user can view those entries in a table view within another view controller.
I haven't really used a plist before therefore my question may sound very silly but regardless I need some help with this.
So far I have the inputs setup but they don't really do anything, I know this question is very basic but I am struggling to find information on this that doesn't go too technical.
I can post my code if that will be beneficial.
Any help will be greatly appreciated.
#property (weak, nonatomic) IBOutlet UILabel *balesFedLabel;
#property (weak, nonatomic) IBOutlet UIStepper *balesFedStepper;
#property (weak, nonatomic) IBOutlet UIPickerView *fieldPickerView;
#property (weak, nonatomic) IBOutlet UILabel *dateLabel;
#property (weak, nonatomic) IBOutlet UITextField *sheepGroup;
#property (strong, nonatomic) IBOutlet UIBarButtonItem *backButton;
//Actions
- (IBAction)stepperValueChange:(id)sender;
- (IBAction)saveButton:(id)sender;
- (IBAction)textFieldDoneEditing:(id)sender;
#property NSArray *dataSource;
#property NSString *tempFieldSelection;
#property(nonatomic) UIKeyboardAppearance keyboardAppearanceDark;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self setupArray];
NSLocale *gbLocale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_GB"];
NSString *dateFormatString = [NSDateFormatter dateFormatFromTemplate:#"dd/MM/yyyy" options:0 locale:gbLocale];
NSLog(#"dataFormatString: %#", dateFormatString);
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:dateFormatString];
NSString *stringFromDate = [dateFormatter stringFromDate:[NSDate date]];
self.dateLabel.text = stringFromDate;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {[self.view endEditing:YES];
}
- (void)setupArray {
_dataSource = [[NSArray alloc] initWithObjects:#"Cow Pasture", #"Top Lot", #"East Lot", #"West Lot", #"Front Meadow", #"Big Meadow", nil];
}
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
return 1;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
return [_dataSource count];
}
- (UIView *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
return [_dataSource objectAtIndex:row];
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
self.tempFieldSelection = [_dataSource objectAtIndex:[pickerView selectedRowInComponent:0]];
}
- (IBAction)stepperValueChange:(id)sender {double baleStepperValue = self.balesFedStepper.value;
self.balesFedLabel.text = [NSString stringWithFormat:#"%.f", baleStepperValue];
}
- (IBAction)textFieldDoneEditing:(id)sender {[sender resignFirstResponder];
}
- (IBAction)saveButton:(id)sender {
NSLog(#"Bales Fed: %#", self.balesFedLabel.text);
NSLog(#"Sheep Group: %#", self.sheepGroup.text);
NSLog(#"Current Field: %#", self.tempFieldSelection);
NSLog(#"Last Date Fed: %#", self.dateLabel.text);
}
Use an NSMutableDictionary and pass it to the destination UIViewController in a property.
For example in your source view controller:
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
dict[#"Bales Fed"] = self.balesFedLabel.text;
dict[#"Sheep Group"] = self.sheepGroup.text;
dict[#"Current Field"] = self.tempFieldSelection;
dict[#"Last Date Fed"] = self.dateLabel.text;
Just pass dict to the destination view controller.
If you want to use a plist these are the two methods available in a NSDictionary class:
- writeToFile:atomically: to write the dictionary to a file (in plist format)
and the class method dictionaryWithContentsOfFile: or the instance method initWithContentsOfFile: to retrieve the dictionary from disk.
In your case, to write the dictionary to a file in plist format:
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSString *filePath = [documentsPath stringByAppendingPathComponent:#"myData.plist"];
[dict writeToFile:filePath atomically:NO];
And in the destination view controller use this code to retrieve the plist from disk:
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSString *filePath = [documentsPath stringByAppendingPathComponent:#"myData.plist"];
NSDictionary *myData = [NSDictionary dictionaryWithContentsOfFile:filePath];
From Apple's documentation for the first method:
This method recursively validates that all the contained objects are property list objects (instances of NSData, NSDate, NSNumber, NSString, NSArray, or NSDictionary) before writing out the file, and returns NO if all the objects are not property list objects, since the resultant file would not be a valid property list.
If the dictionary’s contents are all property list objects, the file written by this method can be used to initialize a new dictionary with the class method dictionaryWithContentsOfFile: or the instance method initWithContentsOfFile:.
I also recommend you to read the guide Property List Programming Guide
Even when i wouldn`t recommend to use a .plist file here is the code to use it:
NSString* plistPath = [[NSBundle mainBundle] pathForResource:#"YOUR_FILE_NAME" ofType:#"plist"];
NSDictionary *plistDic = [NSDictionary dictionaryWithContentsOfFile:plistPath];
As you are just passing small amounts of user entered data from one view controller to another you do not need to use PLists nor CoreData nor NSUserDefaults. These are all suitable for persistent data but from your description it sounds like it is just transient stuff.
Just store the user data in parameters and then pass them forward to the destination ViewController using the prepareForSegue method. See this SO answer for full details.
I know this question has been asked a hundred times here because I have been reading most of the questions about reading and writing to plists in this forum, in fact this is the main reason why I'm posting this question. I'm tired of trying outdated tutorials about this topic. I have tried a few tutorials but most of them are using .xib files or are not using ARC and I usually end up with a bunch of errors.
Does anyone know about a tutorial about reading/writing to a plist that uses storyboards and ARC? In other words an updated tutorial.
All I need is a tutorial that I can reference to have a better understanding on how to persist data using plists.
Thanks a lot
Here is a very simple piece of code that shows how to read and write to a plist. Code is based on this tutorial.
What I have here is basically two labels and two buttons on screen, one button to write the data and the other one is to read the data when clicked, the two labels are to show the first two items from an array (plist), item 0 will be shown in the first label and item 1 will be shown in the the second label.
.m file
-(NSString *)getFilePath
{
NSArray *pathArray = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
return [[pathArray objectAtIndex:0] stringByAppendingPathComponent:#"fruitList.plist"];
}
-(void)saveData
{
NSArray *value = [[NSArray alloc] initWithObjects: #"Orange", #"Apple", nil];
[value writeToFile:[self getFilePath] atomically:YES];
}
-(void)loadData
{
NSString *myPath = [self getFilePath];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:myPath];
if(fileExists)
{
NSArray *values = [[NSArray alloc]initWithContentsOfFile:myPath];
self.labelOne.text = [values objectAtIndex:0];
self.labelTwo.text = [values objectAtIndex:1];
}
}
- (IBAction)writeData:(id)sender
{
[self saveData];
}
- (IBAction)readData:(id)sender
{
[self loadData];
}
.h file
#property (weak, nonatomic) IBOutlet UILabel *labelOne;
#property (weak, nonatomic) IBOutlet UILabel *labelTwo;
-(NSString*) getFilePath;
-(void) saveData;
-(void) loadData;
- (IBAction)writeData:(id)sender;
- (IBAction)readData:(id)sender;
I am slightly confused why the following doesn't work. Can someone enlighten me?
I have one function that returns a filePath:
- (NSString *) lastLocationPersistenceFilePath {
NSString *filePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingString:#"last_location"];
return filePath;
}
Then, in a method triggered by a button, I attempt to save a CLLocation object like so:
// Store this location so it can persist:
BOOL success = [NSKeyedArchiver archiveRootObject:_startLocation toFile:[self lastLocationPersistenceFilePath]];
if (!success) {
NSLog(#"Could not persist location for some reason!");
} else {
NSLog(#"New location has been stored.");
}
In my viewDidLoad:, I attempt to load it:
- (void)viewDidLoad
{
[super viewDidLoad];
// Retrieve last location:
CLLocation *decodedLocation = [NSKeyedUnarchiver unarchiveObjectWithFile:[self lastLocationPersistenceFilePath]];
if (decodedLocation) {
_startLocation = decodedLocation;
} else {
NSLog(#"Decoding failed.");
}
}
The archiving fails which, of course, means I can't decode anything either. I feel like I am missing something obvious/trivial... any pointers?
Simply, it is not possible to write to the the app's resource directory. Instead write to the app's document directory.
Code example"
- (NSString *) lastLocationPersistenceFilePath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory = [paths firstObject];
NSString *filePath = [documentDirectory stringByAppendingPathComponent:#"last_location"];
return filePath;
}
I have opened gallery on a BUTTON click and choose an image.I save image full path
in a string.Now How can i save that string in button.I have to save string into a button so that button can hold the path.I have so many buttons like same in my view.and have to perform the same.The code I have used for saving Image path is written below.
// Get the image from the result
UIImage* image = [info valueForKey:#"UIImagePickerControllerOriginalImage"];
// Get the data for the image as a PNG
NSData* imageData = UIImagePNGRepresentation(image);
// Give a name to the file
NSString * imageName = #"Myimage.png";
// Now, we have to find the documents directory so we can save it
// Note that you might want to save it elsewhere, like the cache directory,
// or something similar.
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* documentsDirectory = [paths objectAtIndex:0];
// Now we get the full path to the file
NSString* fullPathToFile = [documentsDirectory stringByAppendingPathComponent:imageName];
// and then we write it out
[imageData writeToFile:fullPathToFile atomically:NO];
Button = fullPathToFile; ///This is the button
return;
Here the solution to add property to an object like UIButton etc.
UIButton+String.h
#import <Foundation/Foundation.h>
#interface UIButton (String)
#property (nonatomic, retain) NSString *path;
#end
UIButton+String.m
#import "UIButton+String.h"
#import <objc/runtime.h>
#implementation UIButton (String)
static char UIB_PROPERTY_KEY;
#dynamic path;
-(void)setPath:(NSDictionary *)attributes {
objc_setAssociatedObject(self, &UIB_PROPERTY_KEY, path, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(NSString *)path {
return (NSString*)objc_getAssociatedObject(self, &UIB_PROPERTY_KEY);
}
#end
Create a model class, that is a class that has the necessary methods and properties to persist the data, add, delete and obtain the data. The model class can be a singleton to allow app wide access if necessary.
Views should just be used to display or to obtain user input.
I moved some code that will be used multiple times into a class.
I'm not getting errors, but I'm also not getting results. It seems to skip over my class completely.
Ideally, this class is supposed to do NSURL conns and XMLParser stuff to chew up the data feed from our hosting API. I already have this working but wanted to congeal and somewhat normalize/centralize some of the main logic of my code.
The one function 'bdCheckIfFileExistsAndisValid' is supposed to take a string but return BOOL and it isn't being called at all.
Neither is 'bdParsePlaylistXML' that is supposed to take a string and return an array.
I put breakpoints everywhere in my class and none are hit.
I'm new so I'm not sure if I did everything right. Here's some code, thanks in advance.
--------------------CUSTOM CLASS:(.h)
#interface bdXMLParser : NSObject {
NSMutableArray *playlist;
//Playlist XML info
BOOL recordTrackName;
BOOL recordTrackDescription;
BOOL recordTrackThumbnailAbsoluteLocation;
BOOL recordTrackURL;
NSString *TrackName;
NSString *TrackDescription;
NSString *TrackThumbnailAbsoluteLocation;
NSString *TrackURL;
}
-(NSMutableArray*) bdParsePlaylistXML:(NSString *) playlistXMLFileName;
-(BOOL) bdCheckIfFileExistsAndisValid:(NSString *) localFileName;
----------------CUSTOM CLASS (.m):
#import "bdXMLParser.h"
#implementation bdXMLParser
{
NSMutableData *webData;
NSMutableArray *playlist;
NSXMLParser *xmlParserPlaylist;
}
-(NSString*) bdDocumentsDirectory{
NSString* documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
return documentsPath;
}
-(int) bdCheckFileCreationDate:(NSString *) fileName {
//get XML file path
NSString *localFilePath = [[self bdDocumentsDirectory] stringByAppendingPathComponent:fileName];
//local file check
NSFileManager *filemgr;
filemgr = [NSFileManager defaultManager];
NSDictionary* attrs = [filemgr attributesOfItemAtPath:localFilePath error:nil];
NSDate *fileCreationDate = [attrs objectForKey: NSFileCreationDate];
NSDate *rightNow = [NSDate date];
NSTimeInterval lastDiff = [fileCreationDate timeIntervalSinceNow];
int lastDiffINT = round(lastDiff);
NSLog(#"NSFileCreationDate:%#",fileCreationDate);
NSLog(#"CurrentDate:%#",rightNow);
NSLog(#"lastDiff:%f",lastDiff);
return lastDiffINT;
}
-(BOOL) bdCheckIfFileExistsAndisValid:(NSString *) fileName {
//local file check
NSString* foofile = [[self bdDocumentsDirectory] stringByAppendingPathComponent:fileName];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:foofile];
if ((fileExists == YES) && ([self bdCheckFileCreationDate:foofile] > -86400))//(24 hrs = 86400 seconds)
return YES;
else
return NO;
}
HERE's THE VIEW WHERE I'M TRYING TO USE IT:(menu.h)
#import "bdXMLParser.h"
#interface MenuScreenViewController : UIViewController <NSXMLParserDelegate>
- (IBAction)btnPlayerPlayPause:(id)sender;
(menu.m)
- (IBAction)btnPlayerPlayPause:(id)sender {
//if array exists, don't reload xml, dont reparse xml, just go to the view
if (playlist.count == 0){
//Playlist!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//========================================================================
//1st: check to see if we have a local cached xml data
//if we do, check if it is <24hr old and if so load it
//if not, go get it with connection and overwrite/store it
//init blogs NSMutableArray
playlist = [[NSMutableArray alloc] init];
//local file check
bdXMLParser *myParser;
BOOL fileExistsAndValid = NO;
=HERE!==fileExistsAndValid = [myParser bdCheckIfFileExistsAndisValid:PlaylistName];
//1st
if (fileExistsAndValid)//(<24 hrs old)
{
NSLog (#"File fileExistsAndValid");
=AND HERE!!=playlist = [myParser bdParsePlaylistXML:PlaylistName];
NSLog(#"playlist:%u", playlist.count);
//load first track
[self LoadTrack:0];
}
else{
NSLog (#"File doesn't exist");
//call refresh function
//[self refreshAlbumPhotoXML];
[myParser bdRefreshPlaylistXML];
}
}
}
you forgot initing the class
bdXMLParser *myParser= [[bdXMLParster alloc]init];