Save and Get image from plist - ios

I am developing one app in that getting images from array and display vertically in ScrollView.
when user double tapped on particular image i want that exact image store into plist according to tag value of that image, and retrieve that image later on when require.
i tried this one
// Store Data into plist.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask,
YES);
NSString *path = [NSString stringWithFormat:#"%#/myPlist.plist",
[paths objectAtIndex:0]];
// Place an image in a dictionary that will be stored as a plist
NSMutableDictionary * dictionary=[[NSMutableDictionary alloc]init];
[dictionary setObject:ImgView.tag forKey:#"image"];
NSLog(#"%#",dictionary);
// Write the dictionary to the filesystem as a plist
[NSKeyedArchiver archiveRootObject:dictionary toFile:path];
// For getting data from NSmutable array store it to the scrollview.
int m=0;
AppDelegate * delegate=(AppDelegate *)[[UIApplication sharedApplication]delegate];
delegate.front=TRUE;
delegate.back=FALSE;
UIScrollView *scrollView=[[UIScrollView alloc]initWithFrame:CGRectMake(0, 0, 320, 480)];
[scrollView setPagingEnabled:YES];
[scrollView setShowsHorizontalScrollIndicator:NO];
FrontsCards=[[NSMutableArray alloc]initWithObjects:#"cloub1.png",#"cloub2.png",#"cloub3.png",#"cloub4.png",#"cloub5.png",#"cloub6.png",#"cloub7.png",#"cloub8.png",#"cloub9.png",#"cloub10.png",#"cloub11.png",#"cloub12.png",#"diamond1.png",#"diamond2.png",#"diamond3.png",#"diamond4.png",#"diamond5.png", nil];
for(m=0; m<[FrontsCards count];m++)
{
ImgView.alpha=1;
ImgView.tag=m;
int randIdx=arc4random()%[FrontsCards count];
NSString *imageName=[FrontsCards objectAtIndex:randIdx];
NSString *fullImageName=[NSString stringWithFormat:#"%#",imageName];
int padding=0;
CGRect imageViewFrame=CGRectMake(scrollView.frame.size.width*m+padding, scrollView.frame.origin.y, scrollView.frame.size.width-2*padding, scrollView.frame.size.height);
ImgView=[[UIImageView alloc]initWithFrame:imageViewFrame];
[ImgView setImage:[UIImage imageNamed:fullImageName]];
NSLog(#"%d",m);
// Place an image in a dictionary that will be stored as a plist
//[dictionary setObject:image forKey:#"image"];
// Write the dictionary to the filesystem as a plist
//[NSKeyedArchiver archiveRootObject:dictionary toFile:path];
[scrollView addSubview:ImgView];
UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(doubleTapImgView:)];
doubleTap.numberOfTapsRequired = 2;
doubleTap.delegate = self;
[self.ImgView addGestureRecognizer:doubleTap];
self.ImgView.userInteractionEnabled=YES;
}
CGSize scrollViewSize=CGSizeMake(scrollView.frame.size.width*[FrontsCards count], scrollView.frame.size.height);
[scrollView setContentSize:scrollViewSize];
[self.view addSubview:scrollView];
help me out this thanks in advance.

Define this MACRO Definition at the top of your .m file
#define LIB_DIR_PATH NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES)[0]
Use this function to Save Image to Plist with Image and Name
- (void)saveImage:(UIImage *)image WithName:(NSString *)imageName
{
// If File Exist then read it otherwise creat new
NSMutableDictionary *imageInfoDict;
if([[NSFileManager defaultManager] fileExistsAtPath:[LIB_DIR_PATH stringByAppendingPathComponent:#"imageInfo.plist"]])
{
NSData *fileData = [NSData dataWithContentsOfFile:[LIB_DIR_PATH stringByAppendingPathComponent:#"imageInfo.plist"]];
imageInfoDict = [NSMutableDictionary dictionaryWithDictionary:[NSKeyedUnarchiver unarchiveObjectWithData:fileData]];
}
else
imageInfoDict = [NSMutableDictionary dictionaryWithCapacity:0];
// Add Single Image to Dictionary
[imageInfoDict setValue:image forKey:imageName];
// Convert Main info Dictionary to `NSData` to Save on Disc
[NSKeyedArchiver archiveRootObject:imageInfoDict toFile:[LIB_DIR_PATH stringByAppendingPathComponent:#"imageInfo.plist"]];
// To Read Stored Image Use Following Code
[self readImageFromPlistByKey:imageName];
}
This function returns image for respective name from Plist
-(UIImage *)readImageFromPlistByKey:(NSString *)keyName
{
// If File Exist then read it otherwise creat new
NSMutableDictionary *imageInfoDict;
if([[NSFileManager defaultManager] fileExistsAtPath:[LIB_DIR_PATH stringByAppendingPathComponent:#"imageInfo.plist"]])
{
NSData *fileData = [NSData dataWithContentsOfFile:[LIB_DIR_PATH stringByAppendingPathComponent:#"imageInfo.plist"]];
if([fileData length] > 0)
{
// Read Plist
imageInfoDict = [NSMutableDictionary dictionaryWithDictionary:[NSKeyedUnarchiver unarchiveObjectWithData:fileData]];
// Here is your Image
return imageInfoDict[keyName];
}
}
else
{
// Return Default Image if not Found
return [UIImage imageNamed:#"Default.png"];
}
}

If you are going to just store indexes, you need to have a master imageArray. I added insert/delete when user double taps the imageView twice.
- (void)doubleTapImgView:(UITapGestureRecognizer *)recognizer
{
UIImageView *imageView = (UIImageView *)recognizer.view;
[self insertorDeleteImageIndex:imageView.tag-1];
}
- (NSString *)plistFilePath{
NSString *documents = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
return [documents stringByAppendingPathComponent:#"ImageIndexes.plist"];
}
- (void)insertorDeleteImageIndex:(NSInteger)index{
NSString *filePath = [self plistFilePath];
NSMutableArray *savedIndexes = [NSMutableArray arrayWithContentsOfFile:filePath];
if (!savedIndexes) {
savedIndexes = [NSMutableArray array];
}
if (![savedIndexes containsObject:#(index)]) {
[savedIndexes addObject:#(index)];
}else{
[savedIndexes removeObject:#(index)];
}
[savedIndexes writeToFile:filePath atomically:YES];
}
- (NSArray *)savedImageIndexes{
NSString *filePath = [self plistFilePath];
return [NSArray arrayWithContentsOfFile:filePath];
}
Source code

The code you post above can't be the real code as it wouldn't compile. That said, it shows a few errors:
You can't put basic numbers (NSInteger) into a dictionary, it needs to be boxed in an NSNumber.
You're setting the tag of the image before you create the instance of the image view (so either it will do nothing or set the wrong tag).
For saving the image, if you do want to save the image instead of the tag, you need to save it as data. You can store an image inside a dictionary no problem, but if you then want to store your dictionary as a plist you need to convert the image to NSData. You can get the image data using:
UIImageJPEGRepresentation(imageToSave, 0.8)

Related

Upload array of dictionaries to server and then download

I'm currently working on a video editing part where I capture the screenshots and some key values in dictionary. At the end when recording is done, I've an array of dictionaries.
Now I want this array of dictionary to upload to a server and later I want to download that array.
I've tried converting NSMutableArray to bytes and write it into text file and then I download the text file and convert it back to NSMutableArray.
The issue is that the dictionaries inside that NSMutableArray do not have key values.
Any other better way to upload and download this information on a server?
You should seperate your infomation and images.
Then upload them.
There an example:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//------------------This part is for upload------------------
//Upload info
UIImage* sourceImage = [UIImage imageNamed:#"source.png"];
UIImageView* imgV1 = [[UIImageView alloc] initWithFrame:CGRectMake(50, 50, 100, 100)];
imgV1.backgroundColor = [UIColor redColor];
imgV1.image = sourceImage;
[self.view addSubview:imgV1];
NSDictionary* uploadDic = [[NSDictionary alloc] initWithObjectsAndKeys:
#"source.png",#"testImage",
nil];
NSData* uploadData = [NSJSONSerialization dataWithJSONObject:uploadDic options:NSJSONWritingPrettyPrinted error:nil];
NSString* uploadString = [[NSString alloc] initWithData:uploadData encoding:NSUTF8StringEncoding];
//Upload image
NSData* imageData = [NSData dataWithContentsOfFile:#"source.png"];
[self uploadInfoToURL:uploadString andImageData:imageData];
//-----------------------------------------------------------
//------------------This part is for upload------------------
//Download info
NSString *downLoadString = uploadString;
NSData* downLoadData = [downLoadString dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *downLoadDic = [NSJSONSerialization JSONObjectWithData:downLoadData options:NSJSONReadingMutableContainers error:nil];
UIImageView* imgV2 = [[UIImageView alloc] initWithFrame:CGRectMake(50, 250, 100, 100)];
imgV2.backgroundColor = [UIColor blueColor];
[self.view addSubview:imgV2];
//Download image
NSString* downURL = [NSString stringWithFormat:#"http://youServer/%#",[downLoadDic objectForKey:#"testImage"]];
imgV2.image = [self getImageFromURL:downURL];
//-----------------------------------------------------------
}
-(UIImage *) getImageFromURL:(NSString *)fileURL {
NSLog(#"Begin download");
UIImage * result;
NSData * data = [NSData dataWithContentsOfURL:[NSURL URLWithString:fileURL]];
result = [UIImage imageWithData:data];
return result;
}
-(BOOL *) uploadInfoToURL:(NSString *)infoString andImageData:(NSData *)data {
NSLog(#"Begin upload");
//Use http post to upload your image data to you server
// if (nil == error) {
// return YES;
// }
return NO;
}
Hope it can help you.

Threading loading images from a device to a tableView in swift

I can't find anything online about threading loading an image from a device and scrolling smoothly through a tableview. There is one on ray wen about this, but it doesn't really help me for my situation.
Does anybody have any advice or code which would help to allow a tableview to scroll smoothly and load images from the device's temporary directory?
i did exactly as mentioned at tutorial, but with modification for nsoperation subclass
this is methods for fetch
-(void) updateData
{
[self.pendingOperations.downloadQueue addOperationWithBlock:^{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSArray *filePathes = [self recursiveRecordsForResourcesOfType:#[#"png", #"jpeg", #"jpg",#"pdf"] inDirectory:documentsDirectory];
#synchronized (self) {
self.documents = filePathes;
NSLog(#"documents count %#", #([self.documents count]));
}
dispatch_async(dispatch_get_main_queue(), ^(void){
//Run UI Updates
[self.delegate modelDidUpdate:self];
});
}];
}
- (NSArray *)recursiveRecordsForResourcesOfType:(NSArray *)types inDirectory:(NSString *)directoryPath{
NSMutableArray *filePaths = [[NSMutableArray alloc] init];
NSMutableDictionary *typesDic = [NSMutableDictionary dictionary];
for (NSString *type in types)
[typesDic setObject:type forKey:type];
// Enumerators are recursive
NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager] enumeratorAtPath:directoryPath];
NSString *filePath;
while ((filePath = [enumerator nextObject]) != nil){
// If we have the right type of file, add it to the list
// Make sure to prepend the directory path
if([typesDic objectForKey:[filePath pathExtension]]){
//[filePaths addObject:[directoryPath stringByAppendingPathComponent:filePath]];
CURFileRecord *record = [CURFileRecord new];
record.filePath =[directoryPath stringByAppendingPathComponent:filePath];
record.fileName = filePath;
[filePaths addObject:record];
}
}
return filePaths;
}
this is .m for subclass
- (void)main {
// 4
#autoreleasepool {
if (self.isCancelled)
return;
NSData *fileData = [[NSFileManager defaultManager] contentsAtPath:self.fileRecord.filePath];
// self.fileRecord.fileData = fileData;
if (self.isCancelled) {
fileData = nil;
return;
}
if (fileData) {
UIImage *newImage;
if ([[self.fileRecord.filePath pathExtension] isEqualToString:#"pdf"])
{
CGPDFDocumentRef doc = [CURDocumentViewerUtilities MyGetPDFDocumentRef:fileData];
newImage = [CURDocumentViewerUtilities buildThumbnailImage:doc withSize:CGSizeMake(64, 96)];
}
else
{
newImage = [CURDocumentViewerUtilities makePreviewImageFromData:fileData];
}
self.fileRecord.previewImage = newImage;
}
else {
self.fileRecord.failed = YES;
}
fileData = nil;
if (self.isCancelled)
return;
// 5
[(NSObject *)self.delegate performSelectorOnMainThread:#selector(imageDownloaderDidFinish:) withObject:self waitUntilDone:NO];
}
}
With update func i've fetched pathes to proccess, and nsoperation subclass loads images. Works fine with 2000 images in fullhd - smoothly and without any lugs

Having trouble saving NSMutable dictionary to documents. UIImage won't save/display

I have a sticker class and I am saving sticker objects to a NSMutableDictionary. Sticker class below:
#import "Sticker.h"
#implementation Sticker
-(instancetype)initWithTitle:(NSString *)title stickerNO:(int)stickerNO image:(UIImage *)image {
self=[super init];
if(self){
self.title=title;
self.stickerNO=[NSNumber numberWithInt:stickerNO];;
self.image=image;
}
return self;
}
//CODING METHODS//////////////
-(void)encodeWithCoder:(NSCoder *)aCoder{
//choose what we save, these are objects
[aCoder encodeObject:self.title forKey:#"title"];
[aCoder encodeObject:self.stickerNO forKey:#"stickerNO"];
[aCoder encodeObject:self.image forKey:#"image"];
}
-(instancetype)initWithCoder:(NSCoder *)aDecoder
{
self=[super init];
if(self){
self.title=[aDecoder decodeObjectForKey:#"title"];
self.stickerNO=[aDecoder decodeObjectForKey:#"stickerNO"];
self.image=[aDecoder decodeObjectForKey:#"image"];
}
return self;
}
#end
The dictionary is managed by the class StickerManager:
#implementation StickerManager
-(instancetype)init {
self = [super init];
//load the dictionary
NSString *path = [self itemArchivePath];
self.stickerDictionary=[NSKeyedUnarchiver unarchiveObjectWithFile:path];
//if there is no dictionary create it and add the default
if(!self.stickerDictionary) {
NSLog(#"Creating dictionary and adding default");
self.stickerDictionary=[[NSMutableDictionary alloc] init];
[self addDefaultStickers];
[self saveStickerDictionary];
}
//if empty fill it
else if ([self.stickerDictionary count]==0){
NSLog(#"Dictionary exists but it empty");
[self addDefaultStickers];
[self saveStickerDictionary];
}
return self;
}
//add the stickers included in the app bundle
-(void)addDefaultStickers {
Sticker *sticker = [[Sticker alloc] initWithTitle:#“Batman” stickerNO:1 image:[UIImage imageNamed:#“batman.png"]];
[self.stickerDictionary setObject:sticker forKey:sticker.title];
}
-(BOOL)saveStickerDictionary{
NSLog(#"Saving stickers");
//get the path from above
NSString *path = [self itemArchivePath];
return [NSKeyedArchiver archiveRootObject:self.stickerDictionary toFile:path];
}
-(NSString *)itemArchivePath
{
//get the directory
NSArray *documentDirectories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
//set it to a string
NSString *documentDirectory = [documentDirectories firstObject];
//here we call the file items.archive
return [documentDirectory stringByAppendingPathComponent:#"stickers.archive"];
}
#end
If when the StickerManager is init if it is empty or doesn't exist it will create and fill the dictionary with the default stickers by calling addDefaultStickers. This is working for the one sticker I have in the code. I can load and restore the dictionary and use NSLog to check the contents. The sticker is there but for some reason the UIImage is null and I can't display it. I'm really not sure why, I have used the encodeWithCoder for it so shouldn't it work? The odd thing is that if I download a sticker from Parse.com (I have an identical class on it) and then convert that image from NSData to png and save it will work. Could someone give me some pointers please to what might be going wrong here? Thanks
EDIT This is my download from Parse.com code:
- (void)getNewStickersWithCompletionHandler:(stickerCompletionHandler)handler
{
__weak StickerManager *weakSelf = self;
PFQuery *stickersQuery = [PFQuery queryWithClassName:#"sticker"];
[stickersQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if(!error) {
for( PFObject *object in objects) {
NSString *title = object[#"title"];
int stickerNO = [[object objectForKey:#"stickerNO"] intValue];
//DOWNLOAD IMAGE CODE
PFFile *image = object[#"image"];
[image getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
if(!error){
UIImage *image = [UIImage imageWithData:data];
Sticker *sticker = [[Sticker alloc] initWithTitle:title stickerNO:stickerNO image:image];
[weakSelf.stickerDictionary setObject:sticker forKey:sticker.title];
[self saveStickerDictionary];
handler(YES,nil);
}
}];//end get image block
}//end for
}
}];//end download stickers block
}
If I save a sticker to the dictionary this way there are no issues and I can display the image. This is almost identical to the addDefaultStickers, I am saving a UIImage and not saving the NSData. No Idea what is up here..
just for other people's reference the problem was in not first converting the UIImage to NSData. I changed UIImage lines in the aCoder method to below:
[aCoder encodeObject:UIImagePNGRepresentation(self.image) forKey:#"image"];
and in the aDecoder: self.image = [UIImage imageWithData:[aDecoder decodeObjectForKey:#"image"]];
don't totally understand why it was working for NSData that was converted to a UIImage for the Parse download before but it's all working now anyway.

How can I update a UITableView from a dynamically downloaded text file?

I am filling a TableView from a text file. I want to enable the user to download an updated text file and replace the existing content of the TableView with the content of the downloaded file. I am able to download the file and replace the original file. If I close the application and open it again, it loads the updated file.
But the TableView doesn't change while the app is running. When I execute the method to load data from the file into the TableView, I can see, using NSLog, that the method is getting the original data from the file.
What am I doing incorrectly? How can I get the method to see the updated text file instead of the original text file?
Thanks.
#interface
#property (strong, nonatomic) NSArray *tableViewData;
#end
#implementation
/*
When user presses button, IBAction method
- downloads text file
- saves the downloaded file, replacing the original text file
- loads the text file into the TableView data (this is what doesn't work)
- sends a reload message to the TableView
*/
- (IBAction)buttonUpdateTextFile:(UIBarButtonItem *)sender
{
NSString *contentsOfTextFile = [self downloadTextFileFromURL:#"http://www.apple.com/index.html"];
[self saveContentsOfTextFile:contentsOfTextFile toFile:#"tableViewData.txt"];
[self loadDataFromFileWithFileName:#"tableViewData" fileExtension:#"txt"];
[self.tableView reloadData];
}
- (NSString *)downloadTextFileFromURL:(NSString *)textFileURLstring
{
NSURL *textFileURL = [NSURL URLWithString:textFileURLstring];
NSError *error = nil;
NSString *contentsOfTextFile = [NSString stringWithContentsOfURL:textFileURL encoding:NSUTF8StringEncoding error:&error];
return contentsOfTextFile;
}
- (void)saveContentsOfTextFile:(NSString *)contentsOfTextFile toFile:(NSString *)fileName
{
NSString *pathName = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *fileNameWithPath = [pathName stringByAppendingPathComponent:fileName];
if (![[NSFileManager defaultManager] fileExistsAtPath:fileNameWithPath]) {
[[NSFileManager defaultManager] createFileAtPath:fileNameWithPath contents:nil attributes:nil];
[[contentsOfTextFile dataUsingEncoding:NSUTF8StringEncoding] writeToFile:fileNameWithPath atomically:NO];
}
- (void)loadDataFromFileWithFileName:(NSString *)fileName fileExtension:(NSString *)fileExtension
{
NSString *path = [[NSBundle mainBundle] pathForResource:fileName
ofType:fileExtension];
NSString *content = [NSString stringWithContentsOfFile:path
encoding:NSUTF8StringEncoding
error:NULL];
NSString *remainingText = [content mutableCopy];
NSMutableArray *data = [[NSMutableArray alloc] init];
NSRange *substringRange;
while (![remainingText isEqualToString:#""]) {
substringRange = [remainingText rangeOfString:#"/n"];
if (substringRange.location == NSNotFound)
{
currentLine = remainingText;
remainingText = #"";
} else {
substringRange.length = substringRange.location;
substringRange.location = 0;
currentLine = [[remainingText substringWithRange:substringRange] mutableCopy];
// - strip line from remainingText
substringRange.location = substringRange.length + 1;
substringRange.length = remainingText.length - substringRange.length - 1;
remainingText = [[remainingText substringWithRange:substringRange] mutableCopy];
}
[data addObject:currentLine];
}
self.tableViewData = [data copy];
}
I think
self.tableViewData = [data copy];
may be the problem.
I would make data a "private" property of the class. Only init once and then manually add and remove objects to it. Don't use copy.

Writing/loading to/from file

Im trying to learn how to save/load images, and i just don't get why this wont work. Im writing a screenshot to the filesystem like this:
if ([[UIScreen mainScreen] respondsToSelector:#selector(scale)])
UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, [UIScreen mainScreen].scale);
else
UIGraphicsBeginImageContext(self.view.bounds.size);
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData * data = UIImagePNGRepresentation(image);
NSArray *directories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [directories objectAtIndex:0];
NSString *key = [documentsDirectory stringByAppendingPathComponent:#"screenshots.archive"];
[data writeToFile:key atomically:YES];
And in the "init" medthod in my UITableView subclass, i do this:
pics = [[NSMutableDictionary alloc]initWithContentsOfFile:[self dataFilePath]];
dataFilePath method:
- (NSString *)dataFilePath
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
return [documentsDirectory stringByAppendingPathComponent:#"screenshots.archive"];
}
To test if this works i have this delegate method:
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return pics.count;
}
I test it by taking a screenshot, and then initializing my UITableview subclass, but it show no rows. What am i doing wrong?
There are a few key issues with the code that are causing it to not work. You're storing the image data directly to the file and trying to read it back as a dictionary. You'll want to wrap the image in an array first, and write the array to the file. Then you'll want to read the file into an array for the table to display. To sum up the changes:
Change
[data writeToFile:key atomically:YES];
to
NSMutableArray *storageArray = [NSMutableArray arrayWithContentsOfFile:key];
if(!storageArray)
storageArray = [NSMutableArray arrayWithObject:data];
else
[storageArray addObject:data];
[storageArray writeToFile:key atomically:YES];
and change
pics = [[NSMutableDictionary alloc]initWithContentsOfFile:[self dataFilePath]];
to
pics = [[NSArray alloc] initWithContentsOfFile:[self dataFilePath]];

Resources