Xcode Saving NSMutableArray of String & BOOL values - objective-c

I've got a little problem with an Application i am designing at the min but i'm a complete beginner, first of all a little information on what i am trying to accomplish.
I have a plist which populates an NSMutableArray which contains many values each one has a string and a BOOL inside, i can make the program save a copy of the file upon opening the app and load the data into the tableview along with an accessoryview of a checkmark.
now the checkmark works ok and you can select different items and the checkmark only appears on those items none of the others and if you inspect the log the details for each of the items check BOOL is changed but when i come to save a second time the checkmark state is not persisted for when i open the application a second time it just saves it as a 0 everytime.
here is some of my code, any help would be appreciated.
Thanks
Brad
- (void)viewDidLoad {
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"CustomChecklist.plist"];
success = [fileManager fileExistsAtPath:filePath];
NSLog(#"STATUS OF SUCCESS %d",success);
if (!success) {
NSString *path = [[NSBundle mainBundle] pathForResource:#"OriginalChecklist" ofType:#"plist"];
success = [fileManager copyItemAtPath:path toPath:filePath error:NULL];
self.dataArray = [NSMutableArray arrayWithContentsOfFile:filePath];
NSLog(#"IF STATEMENT CREATING THE FILE");
}else {
self.dataArray = [NSMutableArray arrayWithContentsOfFile:filePath];
NSLog(#"IF STATEMENT READING THE FILE");
}
NSLog(#"location information %#", filePath);
[super viewDidLoad];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *kCustomCellID = #"MyCellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kCustomCellID];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kCustomCellID] autorelease];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
}
NSMutableDictionary *item = [dataArray objectAtIndex:indexPath.row];
cell.textLabel.text = [item objectForKey:#"text"];
[item setObject:cell forKey:#"cell"];
BOOL checked = [[item objectForKey:#"checked"] boolValue];
UIImage *image = (checked) ? [UIImage imageNamed:#"checked.png"] : [UIImage imageNamed:#"unchecked.png"];
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
CGRect frame = CGRectMake(0.0, 0.0, image.size.width, image.size.height);
button.frame = frame; // match the button's size with the image size
[button setBackgroundImage:image forState:UIControlStateNormal];
// set the button's target to this table view controller so we can interpret touch events and map that to a NSIndexSet
[button addTarget:self action:#selector(checkButtonTapped:event:) forControlEvents:UIControlEventTouchUpInside];
button.backgroundColor = [UIColor clearColor];
cell.accessoryView = button;
return cell;
}
- (void)viewWillDisappear:(BOOL)animated
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *savePath = [documentsDirectory stringByAppendingPathComponent:#"CustomChecklist.plist"];
NSLog(#"View Will Disappear SAVE location information %#", savePath);
[dataArray writeToFile:savePath atomically:YES];
}

BOOL is not an object, it is a primitive type. Therefore, it cannot be saved (properly) in an array or dictionary. You need to use the NSNumber class to wrap it:
[NSNumber numberWithBool:checked] //this should be added to the dictionary

I am writing this from my phone, so I can't really see all of your code. But I just wanted to say that what you are trying to achieve can probably be solved by using NSUserdefaults instead of saving a file. Have you looked into that?
Oh, and just like Evan said, bool isn't an object. Only objects can be stored in an array.

Is there a reason you are adding the cell to your dictionary? A UITableViewCell is not a property list compatible object, so it could keep your array from saving properly.

Related

xcode async tableview load image move listview images gone

We want to download image and data async to our tableview and we want to cache it not to download it again. We found a code for caching.Here is our code. It works asynchronously but when we scroll table view, images gone and come back(we cant see image for a while). Sometimes wrong image come to wrong cell. What might be the reasons and how can we solve it ?
NSURL *imageURL = [NSURL URLWithString:[NSString stringWithFormat:#"%#%#",[userInfo[0] serverUrl],[estateList[indexPath.row] imgUrl]]];
NSString *key = [imageURL absoluteString];
NSData *data = [FTWCache objectForKey:key];
if (data) {
UIImage *image = [UIImage imageWithData:data];
cell.imageView.image = image;
} else {
cell.imageView.image = [UIImage imageNamed:#"yukleniyor"];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
NSData *data = [NSData dataWithContentsOfURL:imageURL];
[FTWCache setObject:data forKey:key];
UIImage *image = [UIImage imageWithData:data];
dispatch_async(dispatch_get_main_queue(), ^{
cell.imageView.image = image;
});
});
}
Here is that code we found for caching
Header is like this
#import <Foundation/Foundation.h>
#interface FTWCache : NSObject
+ (void) resetCache;
+ (void) setObject:(NSData*)data forKey:(NSString*)key;
+ (id) objectForKey:(NSString*)key;
#end
And .m file is like this
#import "FTWCache.h"
static NSTimeInterval cacheTime = (double)604800;
#implementation FTWCache
+ (void) resetCache {
[[NSFileManager defaultManager] removeItemAtPath:[FTWCache cacheDirectory] error:nil];
}
+ (NSString*) cacheDirectory {
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cacheDirectory = [paths objectAtIndex:0];
cacheDirectory = [cacheDirectory stringByAppendingPathComponent:#"FTWCaches"];
return cacheDirectory;
}
+ (NSData*) objectForKey:(NSString*)key {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *filename = [self.cacheDirectory stringByAppendingPathComponent:key];
if ([fileManager fileExistsAtPath:filename])
{
NSDate *modificationDate = [[fileManager attributesOfItemAtPath:filename error:nil] objectForKey:NSFileModificationDate];
if ([modificationDate timeIntervalSinceNow] > cacheTime) {
[fileManager removeItemAtPath:filename error:nil];
} else {
NSData *data = [NSData dataWithContentsOfFile:filename];
return data;
}
}
return nil;
}
+ (void) setObject:(NSData*)data forKey:(NSString*)key {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *filename = [self.cacheDirectory stringByAppendingPathComponent:key];
BOOL isDir = YES;
if (![fileManager fileExistsAtPath:self.cacheDirectory isDirectory:&isDir]) {
[fileManager createDirectoryAtPath:self.cacheDirectory withIntermediateDirectories:NO attributes:nil error:nil];
}
NSError *error;
#try {
[data writeToFile:filename options:NSDataWritingAtomic error:&error];
}
#catch (NSException * e) {
//TODO: error handling maybe
}
}
#end
Sorry for my previous answer.
I will try to explain the problem:
We have TableView total number of rows and rows of the reserved area of the display. As a result, images with asynchronous load can not be loaded into their cells (because it is inserted as it downloads from the memory).
The solution is very simple, you must assign each ImageView with key and this key associated with the cells of the table.
I resolve this problem by using code from this git (https://gist.github.com/khanlou/4998479)
There are two files on it
UIImageView+Network.h
UIImageView+Network.m
You must include they in your project, or create own class and paste to it.
This class uses FTW/FTWCache from (https://github.com/FTW/FTWCache/tree/master/FTWCache). So you must add to your project this one too.
After that you must to import
#import "UIImageView+Network.h"
in file which will use asynchronous image loading and caching.
And short part of code with TableView using
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"MyTableCell";
MyTableCell *cell = (MyTableCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil){
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"MyTableCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
// construction to call method
// [cell.imageView loadImageFromURL:(NSURL*)url placeholderImage:(UIImage*)placeholder cachingKey:(NSString*)key ];
[cell.thumbnailImageView loadImageFromURL:(NSURL*)url placeholderImage:[UIImage imageNamed:#"no_foto.gif"] cachingKey:(NSString*)[NSString stringWithFormat:#"%d",indexPath.row]];
return cell;
}

Loading Images from JSON to Xcode

I having a bit difficulty loading images from a json file into UIImage - Table Cells in Xcode. I tried to load the images from the server into a NSArray then populating the table view UIImage cells. Is there something that I am missing here?
Image are located on a SQL server.
Thanks for the help.
Here is the server output from the PHP into Xcode. (cover_image)
(
"13497074790148.jpeg",
"13494650900147.png",
"13494606630147.png",
"13494605220147.jpeg",
"13494602920147.jpeg",
"13494601850147.jpeg",
"13491916300147.jpeg"
)
Here is the code in Xcode
NSArray *itemsimages = [[NSArray alloc]initWithArray:[results valueForKeyPath:#"cover_image"]];
self.itemImages = itemsimages;
Here is the code in table cells
UIImage *imageitm = [UIImage imageNamed: [self.itemImages objectAtIndex: [indexPath row]]];
cell.itmImage.image = imageitm;
return cell;
You don't have those images stored locally so it doesn't have any images to display. I suggest using SDWebImage to provide asyncronous image loading from remote location + caching mechanism.
-(void) viewDidLoad
{
NSURL *url = [NSURL URLWithString:#"YOUR URL"];
NSData *data = [NSData dataWithContentsOfURL:url];
NSError *error;
NSMutableDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
NSMutableArray *img = [[NSMutableArray alloc]init];
NSArray *websiteDetails = (NSArray *) [json objectForKey:#"logos"];
for(int count=0; count<[websiteDetails count]; count++)
{
NSDictionary *websiteInfo = (NSDictionary *) [websiteDetails objectAtIndex:count];
imagefile = (NSString *) [websiteInfo objectForKey:#"image_file"];
if([imagefile length]>0)
{
NSLog(#"Imagefile URL is: %#",imagefile);
[img addObject:imagefile];
}
}
//NSarray listofURL
listofURL = img;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"SimpleTableItem";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//this will start the image loading in bg
dispatch_async(concurrentQueue, ^{
NSURL *url = [NSURL URLWithString:[listofURL objectAtIndex:indexPath.row]];
NSData *image = [[NSData alloc] initWithContentsOfURL:url];
//this will set the image when loading is finished
dispatch_async(dispatch_get_main_queue(), ^{
cell.imageView.image = [UIImage imageWithData:image];
});
});
}
return cell;
}
You need to have a proper url in json response or you can store the common part of the url in the code itself and append it later with the image name returned from server.
I did as follows in the same condition
__autoreleasing NSError* error = nil;
id result = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
NSDictionary *dict = ((NSDictionary *) result)[#"result"];
NSString *url = dict[#"imageURL"];
NSData *imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]];
UIImage *image = [[UIImage alloc] initWithData:imageData];
[_buttonImageView setImage:image forState:UIControlStateNormal];
where data is the response returned from server.

Complete FIle List in Table view

The Situation:
I am trying to display a list of files from my app's Documents Directory (iOS) in a UITableView.
The Problem:
When the view loads, instead of listing all the files, it only lists one file (the first one alphabetically)
The Code:
cell.textLabel.text = [NSString stringWithFormat:#"Cell Row #%d", [indexPath row]];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSPredicate *filter = [NSPredicate predicateWithFormat:#"self ENDSWITH '.txt'"];
NSArray *fileListAct = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:documentsDirectory error:nil];
NSArray *FileList = [fileListAct filteredArrayUsingPredicate:filter];
cell.textLabel.text = [NSString stringWithFormat:#"%#",[FileList objectAtIndex:indexPath.row]];
NSLog(#"File List: %#", FileList);
All of the code performs as it should, and even the last NSLog line lists ALL of the file names, but for some reason in the UiTableView it only lists the first file name.
More Info:
I've tried creating a do loop for the last cell.textlabel.text line, but that also requires a while statement (and I couldn't think of what the condition would be).
Any ideas on how to make the UITableView display all file names vs. just the first one?
You need to setup a global NSArray for fileList. The you need to create the array in either viewDidLoad or viewWillAppear:
Example
This is a rough example, and how I would do it, although it hasn't been tested, it should work.
#interface MyViewController () {
NSMutableArray *FileList;
}
#end
#implementation MyViewController
- (void)viewDidLoad:(BOOL)animated
{
[super viewDidLoad];
FileList = [[NSMutableArray alloc] init];
}
/* Setup the array here */
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSPredicate *filter = [NSPredicate predicateWithFormat:#"self ENDSWITH '.txt'"];
NSArray *fileListAct = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:documentsDirectory error:nil];
FileList = [fileListAct filteredArrayUsingPredicate:filter];
}
/* Set the number of cells based on the number of entries in your array */
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [FileList count];
/* this is probably what you are missing and is definitely
the reason you are only seeing 1 cell. */
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
cell.textLabel.text = [NSString stringWithFormat:#"%#",[FileList objectAtIndex:indexPath.row]];
}
#end

Objective-C, iOS, NSKeyedUnarchiver, only getting data in one cell

I tried for loops etc.. but nothing seem to work. I have a textfield and once I hit save, I puts the text in a table cell, If I do it again, the previous entry gets replaced. Basically, I can't seem to add another cell unless I manually addObject to the array. The data get pulled properly I used NSLog and the data saves as well.
I think the problem is here somewhere:
NSFileManager *filemgr;
NSString *docsDir;
NSArray *dirPaths;
filemgr = [NSFileManager defaultManager];
// Get the documents directory
dirPaths = NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
// Build the path to the data file
datafilePath = [[NSString alloc] initWithString: [docsDir
stringByAppendingPathComponent: #"data.archive"]];
tablesubtitles = [[NSMutableArray alloc]init];
tabledata = [[NSMutableArray alloc] init];
// Check if the file already exists
if ([filemgr fileExistsAtPath: datafilePath])
{
NSMutableArray *dataArray;
dataArray = [NSKeyedUnarchiver
unarchiveObjectWithFile: datafilePath];
titlestring = [dataArray objectAtIndex:0 ];
detailsstring = [dataArray objectAtIndex:1];
[tabledata addObject:titlestring];
[tablesubtitles addObject:detailsstring];
}
here is the other method for the actual table:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
{
UITableViewCell *cell = nil;
cell = [tableView dequeueReusableCellWithIdentifier:#"homeworkcell"];
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"homework"];
}
NSString *cellValue = [tabledata objectAtIndex:indexPath.row];
NSString *subtitle = [tablesubtitles objectAtIndex:indexPath.row];
cell.textLabel.text= cellValue;
cell.detailTextLabel.text= subtitle;
cell.textLabel.font = [UIFont systemFontOfSize:14.0];
cell.textLabel.backgroundColor = [ UIColor clearColor];
cell.detailTextLabel.backgroundColor = [UIColor clearColor];
// Configure the cell.
//-----------------------------------------START----------------------------Set image of cell----
cellImage = [UIImage imageNamed:#"checkboxblank.png"];
cell.imageView.image = cellImage;
//--------------------------------------------END---------------------------end set image of cell--
return cell;
}
here is where I'm saving the data:
NSMutableArray *contactArray;
contactArray = [[NSMutableArray alloc] init];
[contactArray addObject:titlefield.text];
[contactArray addObject:detailstextfield.text];
[contactArray addObject:date ];
[NSKeyedArchiver archiveRootObject:
contactArray toFile:datafilePath];
Do you recreate each time table data model?
tablesubtitles = [[NSMutableArray alloc]init];
tabledata = [[NSMutableArray alloc] init];
You should make class variables for this.

Displaying photos from NSDocumentDirectory

I'm developing this application on an iPad.
These codes for a 'Browse' button allows the user to view the photos from the iPad's gallery.
- (IBAction) BrowsePhoto:(id)sender
{
UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init];
imagePickerController.delegate = self;
imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
UIPopoverController *popover = [[UIPopoverController alloc] initWithContentViewController:imagePickerController];
[popover setPopoverContentSize:CGSizeMake(320,320)];
[popover presentPopoverFromRect:CGRectMake(200,200,-100,-100) inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
self.popoverController = popover;
[imagePickerController release];
}
When a photo is selected, it will be stored into the application using NSDocumentDirectory.
- (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:#"SavedImage.png"];
UIImage *image = imageView.image;
NSData *imageData = UIImagePNGRepresentation(image);
[imageData writeToFile:savedImagePath atomically:NO];
}
Now i have to include a 'Display' button on the first screen.
When tapped on the button, it will show a new view (modal view controller) and displays all the photos in thumbnails/tableview from the NSDocumentDirectory.
When a photo is selected, it will be deleted from the NSDocumentDirectory.
How can i do this?
First of all, while storing the image in Documents folder, try storing them with a naming convention like keep a counter variable and give your images names according to it. Some thing like this:
NSString *savedImagePath = [documentsDir stringByAppendingPathComponent:[NSString stringWithFormat:#"%d.png", counter]];
Now, once you've all images stored in documents folder and wish to get all of them you can get them by writing this code:
-(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;
}
}
Once you've got all images you can display them as thumbnails and then when you wish to delete an image use this method:
-(int)removeImage:(NSString*)FileName1
{
NSFileManager *filemanager=[NSFileManager defaultManager];
NSArray *path1=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString *documentdirectory = [path1 objectAtIndex:0];
NSString *filepath=[documentdirectory stringByAppendingPathComponent:FileName1];
if([filemanager fileExistsAtPath:filepath]==TRUE)
{
[filemanager removeItemAtPath:filepath error:nil];
}
return 0;
}
I hope this helps you.
To Populate the table with image you'll need a custom cell. You can refer a tutorial by Apple called AdvancedTableViewCells. It will show you how can you populate your table with images. They have a main thumbnail in every row. You have to customize it and make it 3 or 4 thumbnails as per your requirement. Other than that remove everything from that custom cell.