Image not showing in my UICollectionView - ios

So I've been looking for a solution to this issue, but can't seem to find anything. I have an array that I load with image paths using the below method
- (IBAction)btnPictures:(id)sender {
// Create the next view controller.
ImageGalleryViewController *galleryViewController = [[ImageGalleryViewController alloc] initWithNibName:#"ImageGalleryViewController" bundle:nil];
// Search for paths and get users home directory
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
// get path at first index (in case multiple returned
NSString *documentsDirectory = [paths objectAtIndex:0];
NSArray *dirContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:documentsDirectory error:nil];
NSArray *files = [dirContents filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"pathExtension IN %#", #"png"]];
// Pass the selected object to the new view controller.
[galleryViewController setImageArray:files];
// Push the view controller.
[self.navigationController pushViewController:galleryViewController animated:YES];
}
That image array is then sent to the below method in my UICollectionViewController
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
ImageGalleryViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"ImageGalleryViewCell" forIndexPath:indexPath];
NSLog(#"Image at index %#", [imageArray objectAtIndex:indexPath.row]);
[cell.galleryImage setImage:[UIImage imageWithContentsOfFile:[imageArray objectAtIndex:indexPath.row]]];
[cell setBackgroundColor:[UIColor whiteColor]];
return cell;
}
I verified the objectAtIndex is returning a valid image name through my NSLog, but for some reason the cell is not displaying it.
Any help is greatly appreciated, thanks in advance.

The array returned by -contentsOfDirectoryAtPath: of NSFileManager doesn't provide the full file path but just the name of files and directories. You have to append each values in the array to the path to your Document Directory.
Something like this:
NSString *documentsDirectoryPath = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents"];
NSString *imagePath = [documentsDirectoryPath stringByAppendingPathComponent:[imageArray objectAtIndex:indexPath.row]];
UIImage *image = [UIImage imageWithContentsOfFile:imagePath];

I suspect, you are not initialising any cells before using (dequequing) one. Initialise your cell, and try again. Good Luck!
PS: by initialising I mean, alloc init your cell.

Related

"*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 1 beyond bounds [0 .. 0]'"

I know this is a common question on Stack Overflow, but unfortunately none have been able to lead me to my solution.
I'm trying to list the files in my documents directory in a UITableView. (I also have another tableview displaying devices I'm connected to)
I know I'm getting this error because its saying that my array has 0 objects, and I'm trying to access the object at index 1.
But I have a file in my documents directory.
If I have 2 files, when I delete 1, I get this error. When the app is relaunched, it shows the UITableView correctly with the file deleted.
I got my code from here:
Objective-C: How to list files from documents directory into a UITableView?
this is my content:
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
if (tableView == _tblConnectedDevices){
return [_arrConnectedDevices count];
}
if ([filePathsArray count] > 0){
return [filePathsArray count];
}
else
return 1;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
if (tableView == _tblConnectedDevices){
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"CellIdentifier"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"CellIdentifier"];
}
cell.textLabel.text = [_arrConnectedDevices objectAtIndex:indexPath.row];
return cell;
} else {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
filePathsArray = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:documentsDirectory error:nil];
NSString *last = [documentsDirectory stringByAppendingPathComponent:[filePathsArray objectAtIndex:indexPath.row]];
NSString *last2 = [[last lastPathComponent] stringByDeletingPathExtension];
cell.textLabel.text = last2;
return cell;
}
}
My delete void:
-(IBAction)deleteFile:(id)sender{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask,
YES);
NSString *fullPath = [[paths lastObject] stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.txt", fileName]];
NSError *error;
[[NSFileManager defaultManager] removeItemAtPath:fullPath error:&error];
[_cellView reloadData];
}
Reload your filePathArray in deleteFile: Also set breakpoint and look how many files you have in array
You should refactor your code. However:
I assume that you get the error in this line:
NSString *last = [documentsDirectory stringByAppendingPathComponent:[filePathsArray objectAtIndex:indexPath.row]];
What's going wrong:
A. You have an array with the paths in-memory. When the table view asks you for the number of items, you return the count of that array.
B. When the table view asks for an item in a row, you read the directory. (Well, that's not that fast the method should be.)
filePathsArray = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:documentsDirectory error:nil];
Then you look for the file with the index of indexPath.row:
NSString *last = [documentsDirectory stringByAppendingPathComponent:[filePathsArray objectAtIndex:indexPath.row]];
This "works" (it is akin of working) as long as you have at least as many files in the directory as in your array.
When you remove the file from the directory, it is still an item in the array. So you say to the table view that there are as many rows as items in the array. When the table view tries to get it, you look to the disk and find less files (the deleted is missed). So the array you get from disk has one item less than the items in-memory.
To fix it: Update your in-memory array. Or make a decision: Work in-memory or work on disk.

Rotation of images stored in documents directory

I have written an app that allows the user to take photos which are stored in an NSArray and which are then saved in the Documents directory. When they are reloaded the pictures are stored in an UITableView - note only one photo is currently loaded due to problem 1.
I have two problems:
1 - This works but only for one photo as I need to be able work out how many photos have been stored.
2 - When I reload the data and put into an UIImageView the rotation of the photos is incorrect. Landscape photos are upside down and portrait photos are landscape.
Any help with either of these issues greatly appreciated.
Saving the photos
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
for (int i=0;i<photoCount;i++)
{
UIImage *image = [photos objectAtIndex:i];
NSString *savePicturePath = [saveFolderPath stringByAppendingPathComponent:[NSString stringWithFormat:#"image_%d",i]];
NSData *imageData = UIImagePNGRepresentation(image);
[imageData writeToFile:savePicturePath atomically:NO];
}
Retrieving the photos
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *getPicPath = [documentsDirectory stringByAppendingPathComponent:#"image_0"];
NSData *picData = [[NSFileManager defaultManager] contentsAtPath:getPicPath];
UIImage *loadedImage = [UIImage imageWithData:picData];
[photos addObject:loadedImage];
[self.tableView reloadData];
Adding image to table
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:#"photoCell"];
UIImage *currentImage = [self.photos objectAtIndex:indexPath.row];
cell.imageView.image = currentImage;
return cell;
}
You could solve the first issue by creating your own directory and storing all images to that directory. Then when you read use NSFileManager's contentsOfDirectoryAtPath to get an array of all the images in that directory. Or you could read the content of the documents folder and use NSPredicate to filter out only images by file extension (using filteredArrayUsingPredicate).
As for the rotation issue, the answer is available here.
The rotation issue ... simple:
Change
NSData *imageData = UIImagePNGRepresentation(image);
to
NSData *imageData = UIImageJPGRepresentation(image, 1.0);
And everything is perfect. Thanks to Joel for pointing me in the right direction.

Loading from file not working.

I'm taking screenshots and writing them to file with this code:
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"];
NSMutableArray *storageArray = [NSMutableArray arrayWithContentsOfFile:key];
if(!storageArray)
storageArray = [NSMutableArray arrayWithObject:data];
else
[storageArray addObject:data];
[storageArray writeToFile:key atomically:YES];
When i load the images again i do this:
pics = [[NSArray alloc] initWithContentsOfFile:[self dataFilePath]];
ScreenshotViewController *scv = [[ScreenshotViewController alloc]init];
[[self navigationController]pushViewController:scv animated:YES];
NSInteger row = indexPath.row;
[scv setImage:[pics objectAtIndex:row]];
dataFilePath method:
- (NSString *)dataFilePath
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
return [documentsDirectory stringByAppendingPathComponent:#"screenshots.archive"];
}
The problem is that that the UIImageView, in the ScreenshotViewController remains blank. I have tested all kinds of things, and it is something about the way the images get saved/loaded into the array, but i'm not sure. I have also tested that the actual screenshot part is working by putting it into a UIImageView right away and adding it to the view.
NOTE:
If i change this
[scv setImage:[pics objectAtIndex:row]];
to this
[scv.myUIImageView setImage:[pics objectAtIndex:row]];
i get this exception: [__NSCFData _isResizable]: unrecognized selector sent to instance 0x847a280.
Whats the correct way of setting the image by?
Wow it got abit messy, hope its readable.
At first glance, and assuming your read/write code is correct, you are saving the image with PNG representation.
Thus, when reading, you will need to create a UIImage like this:
UIImage * myPic = [UIImage imageWithData:[pics objectAtIndex:row]];
Then try showing that image

Creating image thumbnails to be loaded into tableview from files in app directory

I need some help for a problem which I can't solve but I think I am close to the solution. Here is it:
In a version of my app, I was able to populate a tableview (in CellforRowAtIndexPath) with images taken from the Assetlibrary using the following 2 lines:
ALAsset someAsset = [theAssets objectAtIndex:indexPath.row];
[cell.imageView setImage:[UIImage imageWithCGImage:[someAsset thumbnail]]];
Now, I am trying to read image files from the directory and stored in an NSMutableArray. I can see the filenames when I NSLog the NSMutableArray. But how do I now cause the files to be converted into images and displayed in my tableview in the same way I did why using the Assetlibrary? I have tried several times, but the app either crashes or it does not show the image thumbnails in the table view. For example, this statement does not display the image but the app does not crash:
UIImage *anImage = [UIImage imageWithContentsOfFile:[self.listTable objectAtIndex:0]];
When I setImage in the next line, it doesn't work. Someone please help!
UPDATED: The contents of self.listable when I NSLog it is something like this: "19-10-25 276-10-12.jpg",
"19-10-37 276-10-12.jpg",
"19-10-54 276-10-12.jpg",
"19-10-65 276-10-12.mov", etc.
When I NSLog my documents directory, it is: /var/mobile/Applications/8CB1368A-AAE2-4815-BD26-A7B7C8536193/Documents.
Apps can only imageWithContentsOfFile for files located within the app's sandbox (e.g. in Documents, the bundle, etc.) If these files are located in your Documents folder, you get the full path via:
NSString *documentsFolder = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *imageFullPath = [documentsFolder stringByAppendingPathComponent:imageFilename];
You can then use that in imageWithContentsOfFile.
Update:
You asked:
my directoryContents is an NSArray; how do I convert it to NSString and then [documentsFolder stringByAppendingPathComponent ...] and store each fullpath in the NSMutableArray?
You might do something like:
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSArray *filenames = [fileManager contentsOfDirectoryAtPath:documentsDirectory error:nil];
NSMutableArray *paths = [[NSMutableArray alloc] initWithCapacity:[filenames count]];
for (NSString *filename in filenames)
{
[paths addObject:[documentsDirectory stringByAppendingPathComponent:filename]];
}
NSLog(#"%s filenames = %#", __FUNCTION__, filenames);
NSLog(#"%s paths = %#", __FUNCTION__, paths);

Displaying NSArray of files in a UITableView - iOS 5

I have an app that allows users to save and open text files. Saving and opening files is fairly straightforward and easy, but I have to give the user an easy way to select a file to open. I decided to do this with a UITableView.
When the TableView loads in my view controller, my goal is to populate the TableView with the names of all of the user's text files from within the Documents folder (part of the iOS App Sandbox).
I have a general idea of how to do this:
Get the contents of the Documents folder and place it in an array
NSString *pathString = [[NSBundle mainBundle] pathForResource:#"Documents" ofType:#"txt"];
NSArray *fileList = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:pathString error:nil];
NSLog(#"Contents of directory: %#", fileList);
But this always returns: (null) in the output window. What is the path for my app's document folder?
Place the array in the UITableView
I figured I'd use the numberOfRowsInSection method to do this. Is this the right place for performing this type of operation? Of should I use a different method?
Finally, the app will get the value of the selected cell and use that value to open the file.
My main question here is: How can I place items (particularly the contents of directory) into an NSArray and then display that array in a UITableView?
Any help is much appreciated!
You can get the path using:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
You can get the contents of the directory using:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSArray *fileList = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:documentsDirectory error:nil];
As for displaying an NSArray in a UITableView, you should review Apple's documentation on UITableView Data Source protocol:
http://developer.apple.com/library/ios/#documentation/uikit/reference/UITableViewDataSource_Protocol/Reference/Reference.html
You use the cellForRowAtIndexPath method to actually populate the table, something like this would work:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MyIdentifier"];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"MyIdentifier"] autorelease];
}
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.textLabel.text = [fileList objectAtIndex:indexPath.row]
return cell;
}

Resources