So I have a download manager in my app. I have taken it upon myself to liven it up today.
I have implemented UITableViewCellStyleSubtitle, and is displaying properly.
I want to add more than 1 line to it. Right now I'm stuck in choosing either the file size or the formatted date.
How would I do both? i.e.
Cell Title
Date: (followed by file size) or
File Size:
Below is the relevant code I'm working with.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [(UITableViewCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier] autorelease];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
[cell setSelectionStyle:UITableViewCellSelectionStyleBlue];
}
// Configure the cell.
cell.textLabel.text = [directoryContents objectAtIndex:indexPath.row];
cell.accessoryType = UITableViewCellAccessoryNone;
[cell.layer setBorderColor:[UIColor colorWithRed:30/255.0 green:30/255.0 blue:30/255.0 alpha:1.0].CGColor];
[cell.layer setBorderWidth:1.5f];
cell.textLabel.numberOfLines = 0;
//Get file size
NSError *error;
NSString *fileName = [directoryContents objectAtIndex:indexPath.row];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [[paths objectAtIndex:0] stringByAppendingPathComponent:#"my folder"];
path = [path stringByAppendingPathComponent:fileName];
NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:&error];
NSInteger fileSize = [[fileAttributes objectForKey:NSFileSize] intValue];
//Setting the date
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSString *filePath = [documentsPath stringByAppendingPathComponent:#"my folder"];
filePath = [filePath stringByAppendingPathComponent:fileName];
NSDate *creationDate = nil;
NSDictionary *attributes = [fileManager attributesOfItemAtPath:filePath error:nil];
creationDate = attributes[NSFileCreationDate];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"MM-dd-yyyy"];
NSString *dateString = [dateFormatter stringFromDate:creationDate];
/////This is where I need to blend the dateString with the file size//////
cell.detailTextLabel.text = [NSString stringWithFormat:dateString, #"%#", [self formattedFileSize:fileSize]];
cell.detailTextLabel.numberOfLines = 2;
return cell;
}
Thank you in advanced.
I tried this out, and for some reason, setting numberOfLines to 2 didn't work for me either, but setting it to anything greater then 2, or setting it to 0 worked.
You need to format your two strings properly. This is not correct syntax,
[NSString stringWithFormat:dateString, #"%#", [self formattedFileSize:fileSize]]
It should be like this,
[NSString stringWithFormat:#"%#\n%#", dateString, [self formattedFileSize:fileSize]];
Figured this out. Just had to tweak around with the format of the string.
cell.detailTextLabel.text = [NSString stringWithFormat:#"%#\n%#", dateString, [self formattedFileSize:fileSize]];
As posting this answer the page refreshed and seen that rdelmar is also correct in his updated post showing the proper syntax.
Credit and thanks to him for the help in helping me think this out.
Related
This question already has an answer here:
Don't have the pictures from directory on CollectionView
(1 answer)
Closed 9 years ago.
I am showing the Pictures in all of the Directories however It does not display the pictures. I am putting NSLog in the code so that I can find out which code is working and I only get "j" in the log. I do not see the "a" in the log. What do you think is wrong?
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
allImagesArray = [[NSMutableArray alloc] init];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSArray *locations = [[NSArray alloc]initWithObjects:#"Bottoms", #"Dress", #"Coats", #"Others", #"hats", #"Tops",nil ];
NSString *fPath = documentsDirectory;
for(NSString *component in locations)
{
fPath = [fPath stringByAppendingPathComponent:component];
}
NSArray *directoryContent = [[NSFileManager defaultManager] directoryContentsAtPath: fPath];
collectionTrash.delegate =self;
collectionTrash.dataSource=self;
for(NSString *str in directoryContent){
NSLog(#"i");
NSString *finalFilePath = [fPath stringByAppendingPathComponent:str];
NSData *data = [NSData dataWithContentsOfFile:finalFilePath];
if(data)
{
UIImage *image = [UIImage imageWithData:data];
[allImagesArray addObject:image];
NSLog(#"array:%#",[allImagesArray description]);
}}
for(NSString *folder in locations) {
// get the folder contents
for(NSString *file in directoryContent) {
// load the image
}
}}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
NSLog(#"j");
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return [allImagesArray count];
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *reuseID = #"ReuseID";
TrashCell *mycell = (TrashCell *) [collectionView dequeueReusableCellWithReuseIdentifier:reuseID forIndexPath:indexPath];
UIImageView *imageInCell = (UIImageView*)[mycell viewWithTag:1];
imageInCell.image = [allImagesArray objectAtIndex:indexPath.row];
NSLog(#"a");
return mycell;
}
Feel free to as for more code.
If you look at the exception, it tells you very precisely what's wrong:
You are trying to calling a 'length' method on an array, which simply does not exist. You want to use count here instead. It's not in the code you posted, though - so just do a search for length and you'll probably find it rather easily if the project isn't huge.
NSString *fPath = [documentsDirectory stringByAppendingPathComponent:locations]; gives you a warning, because locations is an array. Think about it - just doesn't make sense: which of its elements do you want to add to the path?
As I think about it, both errors probably relate to each other: You simply ignored the compile time error - or warning - for the fPath, and now the stringByAppendingPathComponent: method calls length on its parameter, which is a method of the expected NSString.
Bottom line: Do not ignore compiler warnings! If you fix those, you probably reduce crashes, too.
I would want to show all the pictures in my directory however I am creating Folders in the Directory so that I can sort the pictures. I want to show all of the pictures in several folders. I am using the code
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
allImagesArray = [[NSMutableArray alloc] init];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *location=#"Bottoms"#"Top"#"Right"#"Left"#"Down"#"Up";
NSString *fPath = [documentsDirectory stringByAppendingPathComponent:location];
NSArray *directoryContent = [[NSFileManager defaultManager] directoryContentsAtPath: fPath];
collectionTrash.delegate =self;
collectionTrash.dataSource=self;
for(NSString *str in directoryContent){
NSLog(#"i");
NSString *finalFilePath = [fPath stringByAppendingPathComponent:str];
NSData *data = [NSData dataWithContentsOfFile:finalFilePath];
if(data)
{
UIImage *image = [UIImage imageWithData:data];
[allImagesArray addObject:image];
NSLog(#"array:%#",[allImagesArray description]);
}}}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
NSLog(#"j");
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return [allImagesArray count];
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *reuseID = #"ReuseID";
TrashCell *mycell = (TrashCell *) [collectionView dequeueReusableCellWithReuseIdentifier:reuseID forIndexPath:indexPath];
UIImageView *imageInCell = (UIImageView*)[mycell viewWithTag:1];
imageInCell.image = [allImagesArray objectAtIndex:indexPath.row];
NSLog(#"a");
return mycell;
}
If you see my code you can notice that I have put NSLOG i and j. The j comes up but the i does not.... Is my way wrong showing all the pictures that are in several folders? I do not have any error.
If you have multiple folders then you need to iterate over the folders and then the folder contents to process all of it.
While this line:
NSString *location=#"Bottoms"#"Top"#"Right"#"Left"#"Down"#"Up";
Is technically legal, I guess you're thinking it will do some array / iteration thing for you. It won't. It just concatenates all of the strings together. You probably want something more like:
NSArray *locations = #[ #"Bottoms", #"Top", #"Right", #"Left", #"Down", #"Up" ];
Then you can run a loop over the folders and then the contents:
for(NSString *folder in locations) {
// get the folder contents
for(NSString *file in directoryContent) {
// load the image
}
}
I have a app which has a download manager built into it. When a file is downloaded, it gets saved to a folder inside of the documents folder. Now I have implemented a time and date stamp in my table view cell. However, When switching from one view controller back to my table view, the time and date updates to the current time.
Below is my code I'm working with, and as always any help would be appreciated.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease]; } //did the subtitle style
NSUInteger row = [indexPath row];
cell.textLabel.text = [directoryContents objectAtIndex:row];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"EEE, MMM/d/yyyy, hh:mm aaa"];
NSDate *date = nil;
if (indexPath.row == 0)
{
date = [NSDate date];
NSString *dateString = [dateFormatter stringFromDate:date];
cell.detailTextLabel.text = dateString;
}
return cell;
}
tableView:cellForRowAtIndexPath: will be called every time the table is reloaded, and hence the time will be updated to the current time because [NSDate date] will be called again.
Instead of calculating the date in tableView:cellForRowAtIndexPath: you should store it elsewhere (such as in an class level NSMutableArray) and set it when the file finishes downloading. This way it won't be reset each time the table loads.
Decided to circle back to this. I ended up getting it figured out (not that I was working on it this whole time lol).
Anyways heres what I did:
//Setting the date
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSString *filePath = [documentsPath stringByAppendingPathComponent:#"my folder"];
filePath = [filePath stringByAppendingPathComponent:fileName];
NSDate *creationDate = nil;
NSDictionary *attributes = [fileManager attributesOfItemAtPath:filePath error:nil];
creationDate = attributes[NSFileCreationDate];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"MM-dd-yyyy"];
NSString *dateString = [dateFormatter stringFromDate:creationDate];
cell.detailTextLabel.text = dateString;
Hope it helps somebody.
Hi I always seem to get exception when I use objectAtInded method to retrieve NSString from an array. I am reading data from a dictionary which is in the "PropertyList.plist" file.My code is
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *path = [[NSBundle mainBundle] pathForResource:#"PropertyList"
ofType:#"plist"];
names = [[NSDictionary alloc]
initWithContentsOfFile:path];
keys = [[[names allKeys] sortedArrayUsingSelector:
#selector(compare:)] retain];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSUInteger section = [indexPath section];
NSUInteger row = [indexPath row];
NSString *key = [keys objectAtIndex:section];
NSArray *nameSection = [names objectForKey:key];
static NSString *SectionsTableIdentifier = #"SectionsTableIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:SectionsTableIdentifier];
if(cell == nil)
{
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault reuseIdentifier:SectionsTableIdentifier] autorelease];
}
cell.textLabel.text = [nameSection objectAtIndex:row];
return cell;
}
The exception happens on the method "cellForRowAtIndexPath" in the line
cell.textLabel.text = [nameSection objectAtIndex:row];
The error message is
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFDictionary objectAtIndex:]: unrecognized selector sent to instance 0x6832440
The plist file is
Where ever I use "[nameSection objectAtIndex:row];" type of statement it always get exception.
The reason for this can be following
[names objectForKey:key];. This statement could give output a NSMutableDictionary type and you are taking a NSArray from that. OR
If it is an array then use the below code for getting the nameSection
NSMutableArray *nameSection = (NSMutableArray*)[names objectForKey:key];
// using (NSMutableArray*) before the code is for external typecasting to tell the compiler that the output is of NSMutableArray type.
Hope this helps.
EDIT:-
use the method below to get your dictionary from the plist file
-(NSMutableDictionary *) GetDictDataFromPlistFile:(NSString *) fileName
{
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); //1
NSString *documentsDirectory = [paths objectAtIndex:0]; //2
NSString *path = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.plist",fileName]]; //3
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath: path]) //4
{
NSString *bundle = [[NSBundle mainBundle] pathForResource:fileName ofType:#"plist"]; //5
[fileManager copyItemAtPath:bundle toPath: path error:&error]; //6
}
NSMutableDictionary *dictData = [[NSMutableDictionary alloc] initWithContentsOfFile:path];
return dictData;
}
Here, name contains only one key of root.
What you need for name is the value of key Root.
Please retry!
Like #scorpiozj said 'names' contains only key of 'Root'. So what I did I know is not a very good way to do it. I am sure there is some other way. I changed the 'viewDidLoad' method to this,
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *path = [[NSBundle mainBundle] pathForResource:#"PropertyList"
ofType:#"plist"];
names = [[NSDictionary alloc]
initWithContentsOfFile:path];
keys = [names allKeys];
NSString *key = [keys objectAtIndex:0];
names = [names objectForKey:key];
keys = [[[names allKeys] sortedArrayUsingSelector:#selector(compare:)] retain];
NSLog(#"keys = %# names = %#",keys,names);
}
It works! Any idea how to do it better will be appreciated though.
I am trying to list the contents of Ringtones directory in a TableView, however, I am only getting the last file in the directory in ALL cells, instead of file per cell. This is my code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
Profile_ManagerAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
cell.hidesAccessoryWhenEditing = YES;
}
cell.accessoryType = UITableViewCellAccessoryNone;
//cell.textLabel.text = #"No Ringtones";
//cell.textLabel.text = #"Test";
NSString *theFiles;
NSFileManager *manager = [NSFileManager defaultManager];
NSArray *fileList = [manager directoryContentsAtPath:#"/Test"];
for (NSString *s in fileList){
theFiles = s;
}
cell.textLabel.text = theFiles;
return cell;
}
It loads fine, no errors, when I use NSLog it lists all the files in the directory just fine. I even tried [s objectAtIndex:indexPath.row] but i get objectAtIndex: error. Anyone have any ideas?
I actually love asking questions on here, cause in less than 10 minutes, I answer my own question!
This is how I got the above code to work:
NSMutableArray *theFiles;
NSFileManager *manager = [NSFileManager defaultManager];
NSArray *fileList = [manager directoryContentsAtPath:#"/Test"];
for (NSString *s in fileList){
theFiles = fileList;
}
cell.textLabel.text = [theFiles objectAtIndex:indexPath.row];
return cell;
I just made the NSString an NSMutableArray, and that allowed me to use the objectAtIndex. Now to trim the file extension!
You should remove NSString,NSMutableArray and for loop.. the final code should be like this:
NSFileManager *manager = [NSFileManager defaultManager];
NSArray *fileList = [manager directoryContentsAtPath:#"/Test"];
cell.textLabel.text = [fileList objectAtIndex:indexPath.row];
return cell;
BTW, this fileList and manager created repeatedly for each cell.. So it is better to make it a global variable for UITableViewController and assign only 1
Your for loop is just iterating over the files and setting theFiles to the current path. So at the end of the loop, theFiles will just be the last string in the collection.
Try something like:
cell.textLabel.text = [fileList objectAtIndex:indexPath.row];