Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I have an error saying Incompatible pointer types sending NSArray to parameter of NSString. I also have used instruments and is very weird that as soon as my app start its around 90mb in memory. What is wrong with my code.
#interface TrashViewController ()
#end
#implementation TrashViewController {
NSMutableArray *Trash ;
}
#synthesize collectionTrash;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
filenames = [[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 stringByAppendingPathComponent:locations];
NSArray *directoryContent = [[NSFileManager defaultManager] directoryContentsAtPath: fPath];
collectionTrash.delegate =self;
collectionTrash.dataSource=self;
for(NSString *str in directoryContent)
{
NSString *finalFilePath = [fPath stringByAppendingPathComponent:str];
[filenames addObject:finalFilePath];
}
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
NSLog(#"j");
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return [filenames count];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"ReuseID";
TrashCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
UIImageView *imageInCell = (UIImageView*)[cell viewWithTag:1];
NSString *cacheKey = filenames[indexPath.item];
imageInCell.image = [self.imageCache objectForKey:cacheKey];
if (imageInCell.image == nil) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
UIImage *image = [UIImage imageWithContentsOfFile:filenames[indexPath.item]];
if (image) {
[self.imageCache setObject:image forKey:cacheKey];
dispatch_async(dispatch_get_main_queue(), ^{
TrashCell *updateCell = (id)[collectionView cellForItemAtIndexPath:indexPath];
UIImageView *imageInCell = (UIImageView*)[updateCell viewWithTag:1];
imageInCell.image = image;
});
}
});
}
return cell;
}
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
NSLog(#"s:%d", [Trash count]);
NSString *trashBin = [Trash objectAtIndex:indexPath.row];
NSLog(#"k%#l",trashBin);
[filenames removeObjectAtIndex:indexPath.row];
[Trash removeObjectAtIndex:indexPath.row];
[self deleteMyFiles:trashBin];
[collectionView deleteItemsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil]];
}
NSString *myFileName;
-(void) deleteMyFiles:(NSString*)filePath {
NSError *error;
if([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
[[NSFileManager defaultManager] removeItemAtPath:filePath error:&error];
} else {
NSLog(#"%#",filePath);
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
[self.imageCache removeAllObjects];
}
eYour problem is in line 5 of viewDidLoad. The method signature for -stringByAppendingPathComponent is
- (NSString *)stringByAppendingPathComponent:(NSString *)aString
Note that it expects a String, but you are passing an Array.
What you probably want to do is change
NSString *fPath = [documentsDirectory stringByAppendingPathComponent:locations];
To something like
NSInteger someIndex = 0; //this will pick the first object in locations, e.g. #"Bottoms".
NSString *fPath = [documentsDirectory stringByAppendingPathComponent:[locations objectAtIndex:someIndex]];
locations is an Array of Strings, so you need to pick one and not pass the entire Array.
Also, next time please dont just dump your code in here, but tell us which line caused the error. You are much more likely to get a quick response if you can point to the part that couses the problems.
Related
I'm having a problem with a custom collection view of PFImages taking up way too much memory. In Parse, I've only got 7 objects, but the memory is reaching up to 1.1 gigabytes when loading the collection view. Also, the memory is not deallocating when leaving the view.
Here's my code
Custom cell
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self setup];
}
return self;
}
- (id)initWithCoder:(NSCoder *)anotherDecoder {
self = [super initWithCoder:anotherDecoder];
if (self) {
[self setup];
}
return self;
}
- (void)setup {
self.pictureImageView = [[PFImageView alloc]init];
self.pictureImageView.frame = CGRectMake(0, 0, self.pictureView.frame.size.width, self.pictureView.frame.size.height);
[self.contentView addSubview:pictureImageView];
}
Collection View Code
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
PicturesCollectionViewCell *cell = (PicturesCollectionViewCell *) [collectionView dequeueReusableCellWithReuseIdentifier:#"cell" forIndexPath:indexPath];
tempObject = [picturesArray objectAtIndex:indexPath.row];
PFFile *file = [tempObject objectForKey:#"thumbnail"];
cell.pictureImageView.file = file;
cell.pictureImageView.image = [UIImage imageNamed: #"LOADING.png"];
[cell.pictureImageView loadInBackground];
cell.pictureImageView.contentMode = UIViewContentModeScaleAspectFill;
cell.titleLabel.text = [tempObject objectForKey:#"title"];
NSLog(#"Image: %#, File: %#, at index: %li", cell.pictureImageView.image, cell.pictureImageView.file, indexPath.row);
return cell;
}
Parse is terrible with this situation... the code will trigger a purge when it gets a memory warning, this helps sometimes:
- (void)removeCacheFiles {
[PFQuery clearAllCachedResults];
NSString *cacheDir = [NSSearchPathForDirectoriesInDomains(
NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *nsurlDir =
[[NSString alloc] initWithFormat:#"%#/YOUR_BUNDLE_ID", cacheDir];
NSFileManager *manager = [NSFileManager defaultManager];
// grab all the files in the documents dir
NSArray *allFiles = [manager contentsOfDirectoryAtPath:nsurlDir error:nil];
// filter the array for only sqlite files
NSPredicate *fltr = [NSPredicate predicateWithFormat:#"self ENDSWITH '.db'"];
NSArray *dbFiles = [allFiles filteredArrayUsingPredicate:fltr];
// use fast enumeration to iterate the array and delete the files
for (NSString *dbFile in dbFiles) {
NSError *error = nil;
[manager removeItemAtPath:[nsurlDir stringByAppendingPathComponent:dbFile]
error:&error];
if (error != nil) {
NSLog(#"Error:%#", [error description]);
} else {
NSLog(#"DB FILE Cleared: %#", dbFile);
}
}
}
Hi in my application in trying display the Flickr images in my UICollectionView but it shows a empty View Control
My code for display the Flickr images.
{
NSMutableArray *photoURLs;
NSMutableArray *photoSetNames;
NSMutableArray *photoids;
}
viewDidLoad code.
- (void)viewDidLoad
{
[super viewDidLoad];
photoURLs = [[NSMutableArray alloc] init];
photoSetNames = [[NSMutableArray alloc] init];
photoids = [[NSMutableArray alloc] init];
[self loadFlickrPhotos];
[self.collectionview reloadData];
}
- (void)loadFlickrPhotos {
NSString *urlString = [NSString stringWithFormat:#"https://www.flickr.com/services/rest/?method=flickr.photosets.getPhotos&format=json&api_key=a6a0c7d5efccffc285b0fe5ee1d938e3&photoset_id=72157644758906604&per_page=10&nojsoncallback=1",nil];
NSLog(#"the url string==%#",urlString);
NSURL *url = [NSURL URLWithString:urlString];
NSString *jsonString = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];
NSLog(#"the str==%#",jsonString);
NSDictionary *results = [NSJSONSerialization JSONObjectWithData:[jsonString dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil];
NSArray *photosets = [[results objectForKey:#"photosets"] objectForKey:#"photoset"];
for (NSDictionary *photoset in photosets) {
NSString *title = [[photoset objectForKey:#"title"] objectForKey:#"_content"];
NSLog(#"title==%#",title);
[photoSetNames addObject:(title.length > 0 ? title : #"Untitled")];
NSString *primary = [photoset objectForKey:#"primary"];
NSString *server = [photoset objectForKey:#"server"];
NSString *secret = [photoset objectForKey:#"secret"];
NSString *farm = [photoset objectForKey:#"farm"];
NSString *urlstr=[NSString stringWithFormat:#"http://farm%#.staticflickr.com/%#/%#_%#.jpg",farm,server,primary,secret];
NSLog(#"your photo id==%#",urlstr);
[photoids addObject:urlstr];
}
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return [photoids count];
}
- (NSInteger)numberOfSectionsInCollectionView: (UICollectionView *)collectionView {
return 1;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier =#"Cell";
imggpolitical *cell=(imggpolitical *) [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath: indexPath];
cell.imageview.image=[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#",[photoids objectAtIndex:indexPath.row]]]]];
return cell;
}
I have used the above to display the Flickr images in UICollectionView but its coming as a empty view please tell me how to resolve this issue.
Thanks.
At the end of -(void)loadFlickrPhotos method, call reloadData on your UICollectionView. You need to tell UICollectionView to refresh its data.
Try [self.collectionview reloadData]
I don't see that you're assigning a delegate or data source. Or for that matter, created your UICollectionView.
When I load the images to show to the UICollectionView I load all the images from the array like this
- (void)viewDidLoad
{
allImagesArray = [[NSMutableArray alloc] init];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *location=#"Others";
NSString *fPath = [documentsDirectory stringByAppendingPathComponent:location];
NSArray *directoryContent = [[NSFileManager defaultManager] directoryContentsAtPath: fPath];
collectionOthers.delegate =self;
collectionOthers.dataSource=self;
for(NSString *str in directoryContent)
{
NSString *finalFilePath = [fPath stringByAppendingPathComponent:str];
NSData *data = [NSData dataWithContentsOfFile:finalFilePath];
if(data)
{
UIImage *image = [UIImage imageWithData:data];
[allImagesArray addObject:image];
NSLog(#"array:%#",[allImagesArray description]);
image = nil;
}
finalFilePath=nil;
data=nil;
}
paths= nil;
documentsDirectory= nil;
location= nil;
fPath= nil;
directoryContent = nil;
}
This is the biggest issue in my app since it uses so many memory. It is because number and size of the images, this could just take up memory. I would only want to load images when they are needed, and discard them when they are no longer needed.However I do not know where and how to change my code so that it will be that way. I am doing this for three month or so and I really need help.
Update
This is my code for the specific part
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *reuseID = #"ReuseID";
OthersCell *mycell = (OthersCell *) [collectionView dequeueReusableCellWithReuseIdentifier:reuseID forIndexPath:indexPath];
UIImageView *imageInCell = (UIImageView*)[mycell viewWithTag:1];
imageInCell.image = [allImagesArray objectAtIndex:indexPath.row];
NSLog(#"a");
return mycell;
}
Clearly, you should load the images just-in-time. One should never hold an array of images (because they take up a lot of memory), but rather just hold an array of filenames. So I'm suggesting you retire allImagesArray and instead define a NSMutableArray called filenames. You could then create the UIImage objects on the fly:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"Cell";
OthersCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
UIImageView *imageInCell = (UIImageView*)[cell viewWithTag:1];
imageInCell.image = [UIImage imageWithContentsOfFile:filenames[indexPath.item]];
return cell;
}
This, assumes, of course, that you populated this NSMutableArray of filenames in viewDidLoad:
- (void)viewDidLoad
{
filenames = [[NSMutableArray alloc] init];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *location=#"Others";
NSString *fPath = [documentsDirectory stringByAppendingPathComponent:location];
NSArray *directoryContent = [[NSFileManager defaultManager] directoryContentsAtPath: fPath];
collectionOthers.delegate =self;
collectionOthers.dataSource=self;
for(NSString *str in directoryContent)
{
NSString *finalFilePath = [fPath stringByAppendingPathComponent:str];
[filenames addObject:fileFilePath];
}
}
This has a problem, though, because imageWithContentsOfFile (as well as loading it into a NSData first and then doing imageWithData) is a bit slow if the images aren't tiny. On slower devices, this can result in a slight stuttering of a quick scroll of a collection view. So, a better approach would be to (a) load the images asynchronously; (b) use a NSCache to optimize performance for when you scroll backwards.
So, first, define a cache:
#property (nonatomic, strong) NSCache *imageCache;
And, instantiate this in viewDidLoad:
self.imageCache = [[NSCache alloc] init];
self.imageCache.name = #"com.company.app.imageCache";
And then, cellForItemAtIndexPath can (a) set the image from the cache; and (b) if not found, retrieve the image asynchronously updating cache and cell appropriately, e.g.:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"Cell";
OthersCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
UIImageView *imageInCell = (UIImageView*)[cell viewWithTag:1];
NSString *cacheKey = filenames[indexPath.item];
imageInCell.image = [self.imageCache objectForKey:cacheKey];
if (imageInCell.image == nil) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
UIImage *image = [UIImage imageWithContentsOfFile:filenames[indexPath.item]];
if (image) {
[self.imageCache setObject:image forKey:cacheKey];
dispatch_async(dispatch_get_main_queue(), ^{
OthersCell *updateCell = (id)[collectionView cellForItemAtIndexPath:indexPath];
UIImageView *imageInCell = (UIImageView*)[updateCell viewWithTag:1];
imageInCell.image = image;
});
}
});
}
return cell;
}
And, obviously, make sure you purge the cache if you receive memory warnings (in iOS 7, the cache doesn't always automatically purge itself under pressure like it used to do):
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
[self.imageCache removeAllObjects];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath
This is the method in which you should be loading the images.
In viewDidLoad, I'd build the array of NSString file paths to each image, then I'd use the collectionView:cellForItemAtIndexPath: method to load the image from the specific file path for this particular cell.
In viewDidLoad You could just load a list of available images. So remove the for loop: for(NSString *str in directoryContent) { ... } loop there (EDIT: or make it a simple for loop, just to populate an array with filenames for the files having data).
When you update a specific collectionviewcell in collectionView:cellForItemAtIndexPath:, just load the image (only 1). The cell will now hold the image data instead of your view controller. So when the cell is released, so is the image data.
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
}
}