This question already has answers here:
The best way to remove duplicate values from NSMutableArray in Objective-C?
(14 answers)
Closed 9 years ago.
Hi Iam working with Iphone Photo Library. I got all photos from photo library with AssetFramework. I displayed those photos in scrollview and are perfectly displaying and images count is assume 6. Then when iam clicking single image, it will show large image. it is also done. my problem is "count is 12 (double count) when clicking image to show it as large."
I used below code to get images:
- (void)createScrollView
{
#try
{
NSLog(#"in create scrollview");
//add views to scrolview
// UIImageView *backgroundImgView;
int x=5;
int y=7;
NSLog(#"assetsArray/count/createScrollview %d",assetsArray.count);
for (int i=0;i<[assetsArray count];i++)
{
UIView *userView=[[UIView alloc] initWithFrame:CGRectMake(x, y, 70, 80)];
userView.tag=i;
UIImageView *backgroundImgView=[[UIImageView alloc] initWithFrame:CGRectMake(1, 1, 70, 70)];
backgroundImgView.tag=1;
// [backgroundImgView setImageWithURL:[NSURL URLWithString:[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF16BigEndianStringEncoding]] placeholderImage:[UIImage imageNamed:#"NoImage.png"]];
//-------------Getting Images from AssetsLibrary ----------
ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *myasset)
{
galleryObj=[[GalleryObject alloc]init];
ALAssetRepresentation *rep = [myasset defaultRepresentation];
CGImageRef iref = [rep fullResolutionImage];
UIImage *assetsLibraryImage;
if (iref)
{
assetsLibraryImage = [UIImage imageWithCGImage:iref scale:[rep scale] orientation:(UIImageOrientation)[rep orientation]];
galleryObj.galleryImage=assetsLibraryImage;
}
else
{
assetsLibraryImage = [UIImage imageNamed:#"NoImage.png"];
}
//[set addObject:[NSString stringWithFormat:#"1"]];
[uniqueSet addObject:galleryObj];
NSLog(#"uniqueSet data is .....%#",uniqueSet); // Output (3,1,4,2,5) ... all objects
[imagesArray addObject:galleryObj];
NSLog(#"imagesArray/resultBlock count is %d array is %#....",imagesArray.count,imagesArray);
backgroundImgView.image=assetsLibraryImage;
};
ALAsset *al_asset = [assetsArray objectAtIndex:i];
//NSLog(#"al_asset is ......%#",al_asset);
al_assetUrl=al_asset.defaultRepresentation.url;
//NSLog(#"al_assetUrl is %#",al_assetUrl);
ALAssetsLibraryAccessFailureBlock failureblock = ^(NSError *myerror)
{
NSLog(#"ALAssetsLibraryAccessFailureBlock");
};
ALAssetsLibrary* assetslibrary = [[ALAssetsLibrary alloc] init];
[assetslibrary assetForURL:al_assetUrl resultBlock:resultblock failureBlock:failureblock];
//-------------Getting Images from AssetsLibrary ----------
UIButton *userButton=[[UIButton alloc]initWithFrame:CGRectMake(1, 1, 70,70)];
[userButton addTarget:self action:#selector(userImageClicked:) forControlEvents:UIControlEventTouchUpInside];
userButton.tag=i;
[userView addSubview:backgroundImgView];
[userView addSubview:userButton];
[self.galleryScrollview addSubview:userView];
x+=79;
if ((i+1)%4==0)
{
//if added image is 4th image
y+=80;
x=5;
}
// [activity stopAnimating];
}
if (y+100>self.galleryScrollview.frame.size.height)
{
self.galleryScrollview.contentSize=CGSizeMake(320, y+100);
}
else
{
self.galleryScrollview.contentSize=CGSizeMake(320, self.galleryScrollview.frame.size.height+60);
}
}
#catch (NSException *exception)
{
NSLog(#"exception is %#",exception);
}
}
Please notice that i created button and action is userImageClicked in above method. when iam clicking userImageClicked button, the array count is double.
i dont know why this is happened. i try to remove duplicates using containsObject method. but no use.
In above method, I saved UIImage in objectclass and assinging that object to imagesArray.
I also took NSMutableSet to store value, but it is also no use.
Please any one can suggest to solve my issue.
This is how you delete duplicate data:
NSArray *copy = [mutableArray copy];
NSInteger index = [copy count] - 1;
for (id object in [copy reverseObjectEnumerator]) {
if ([mutableArray indexOfObject:object inRange:NSMakeRange(0, index)] != NSNotFound) {
[mutableArray removeObjectAtIndex:index];
}
index--;
}
Please use it accordingly...
A simpler way:
NSMutableArray *unique = [NSMutableArray array];
for (id obj in originalArray) {
if (![unique containsObject:obj]) {
[unique addObject:obj];
}
}
If above is the only method where you add images to imagesArray then try checking you are not calling it twice from any where, else check if imagesArray is not getting updated from any where else.
And if you need to call this method createScrollView more than once then write code for adding image in imagesArray separately.
The problem is in the creation of galleryObj.
You create a new object for every image.
Every instance of galleryObj is therefore unique.
Whether you use NSSet of NSMutableArray or NSWhatever, they will not know that inside the galleryObj object is the same UIImage.
The Apple documentation of ALAssetRepresentation states that it encapsulates one of the representations. So if you have both a JGP and a RAW picture saved, you will get two separate representations of the same picture.
In that case you have to ignore one or the other type. I would not recommend comparing a RAW picture with a JPG picture (;-)).
Hi Thank all for quick reply. after 3 hours i solved my problem. I got exact duplicates, so that i removed duplicates using below code. i know it is not good code. but it solves my issue.
if([imagesArray count]>0)
{
int dupCount=[imagesArray count]/2;
int imagesArrayCount=[imagesArray count];
for(int i=dupCount;dupCount<imagesArrayCount;dupCount++)
{
[imagesArray removeObjectAtIndex:i];
}
}
and also i find why the duplicate data is? the answer is i used the block code, it is calling two times. so that array contains double data values.
Thanks you all..
Related
I have a sprite sheet in my documents directory. The sprites sheet consists of 256 icons.
I have a table view, in which for each row I am creating 3 buttons with background images from the sliced part of the sprite sheet.
Below is the code to extract the sliced icon from sprite. Using the coordinates known
-(UIImage *)getSlicedImageForDictionary:(NSDictionary *)spriteInfoDictionary spriteImageRef:(UIImage *)spriteImageReference{
NSString *frameString = [spriteInfoDictionary objectForKey:#"frame"];
NSString *frameStringWithOnlyCommas = [[[frameString stringByReplacingOccurrencesOfString:#"\"" withString:#""] stringByReplacingOccurrencesOfString:#"{" withString:#""] stringByReplacingOccurrencesOfString:#"}" withString:#""];
NSArray *frameValues = [frameStringWithOnlyCommas componentsSeparatedByString:#","];
CGImageRef cgIcon = CGImageCreateWithImageInRect(spriteImageReference.CGImage, CGRectMake([[frameValues objectAtIndex:0] floatValue], [[frameValues objectAtIndex:1] floatValue], [[frameValues objectAtIndex:2] floatValue], [[frameValues objectAtIndex:3] floatValue]));
UIImage *icon = [UIImage imageWithCGImage:cgIcon];
frameString = nil;
frameStringWithOnlyCommas = nil;
frameValues = nil;
CGImageRelease(cgIcon);
return icon;
}
I am calling the above method in the for loop as below,
for (int i = 0; i < [iconInfoArray count]; i ++) {
NSDictionary *currentBook = [spriteInfoDictionary objectForKey:[iconInfoArray objectAtIndex:i]];
articleMetaData.articleImage = [self getSlicedImageForDictionary:currentBook spriteImageRef:self.spriteImageSource];
[spriteIconsArray addObject:articleMetaData];
}
The problem is,
When I set the buttons in the table view from the spriteIconsArray I am getting the "Received memory warning" problem and the application crashes.
[btn setBackgroundImage:[spriteIconsArray objectAtIndex:i] forState:UIControlStateNormal];
But when I write the image reference to the documents directory I am not getting any memory warnings and the application runs smoothly.
NSData *data = UIImagePNGRepresentation([spriteIconsArray objectAtIndex:i]);
NSString *pathOfTempImage = [[NSHomeDirectory() stringByAppendingPathComponent:#"Documents"] stringByAppendingPathComponent:#"tempIcon.png"];
[data writeToFile:pathOfTempImage atomically:YES];
[btn setBackgroundImage:pathOfTempImage forState:UIControlStateNormal];
I am confused why this is happening. I don't want to write the image to the documents and read it again, which may create some latency for large set of data.
Please suggest me in this.
Thanks
Please find the below code for fetching images from Photo library
- (void) initilizeAssetForPhotoLibrary {
if (!assets) {
assets = [[NSMutableArray alloc] init];
} else {
[assets removeAllObjects];
}
ALAssetsGroupEnumerationResultsBlock assetsEnumerationBlock = ^(ALAsset *result, NSUInteger index, BOOL *stop) {
if (result) {
[assets addObject:result];
}
};
ALAssetsFilter *onlyPhotosFilter = [ALAssetsFilter allPhotos];
[assetsGroup setAssetsFilter:onlyPhotosFilter];
[assetsGroup enumerateAssetsUsingBlock:assetsEnumerationBlock];
}
- (NSMutableArray *) getImagesFromPhotoLibrary {
for(int i=0; i<assets.count; i++) {
ALAsset *asset = [assets objectAtIndex:i];
ALAssetRepresentation *assetRepresentation = [asset defaultRepresentation];
UIImage *getImage = [UIImage imageWithCGImage:[assetRepresentation fullScreenImage] scale:[assetRepresentation scale] orientation:(UIImageOrientation)[assetRepresentation orientation]];
[arrImages addObject:getImage];
}
return arrImages;
}
Actually my requirement is that I need to load all image from specific album in application for creating the slideshow.
When I am loading less than 100 images then it works fine but above it gets memory warning and after that it crashed.
Please help me if anyone has different idea to load images and less memory consumption. Thanks in advanced.
Keep all the images in memory will not do, there is just not enough memory for this.
You will need to fill the array with the ALAssetRepresentation of the images and load the image only when you are ready to display it. This way you will only have the image in memory that you are really displaying.
then write down below code and let me know it is working or not!!!
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
(unsigned long)NULL), ^(void) {
for(int i=0; i<assets.count; i++) {
ALAsset *asset = [assets objectAtIndex:i];
ALAssetRepresentation *assetRepresentation = [asset defaultRepresentation];
UIImage *getImage = [UIImage imageWithCGImage:[assetRepresentation fullScreenImage] scale:[assetRepresentation scale] orientation:(UIImageOrientation)[assetRepresentation orientation]];
[arrImages addObject:getImage];
}
return arrImages;
});
Happy Coding...!!!!
I'm facing an issue with the ALAsset library: I have an UIView with 100 image views. When the view is loading, i'm calling a function for generating the images from the file name.
This is my class:
#interface myClass
{
NSString *fileName;
int pathId;
}
viewDidLoad
-(void)viewDidLoad
{
NSMutableArray *imageCollectionArray = [self createImage:arrayOfmyClassObject];
//Here I'm binding the 100 images in UIView using the images in imageCollectionArray
}
This is my method in which I found the issue:
- (NSMutableArray *)createImage:(NSMutableArray *)imageFileNamesArray
{
imageArray = [[NSMutableArray alloc] init];
for (int imageNameKey = 0; imageNameKey<100; imageNameKey++)
{
myClass *obj= [imageFileNamesArray objectAtIndex:imageNameKey];
if(obj.pathId == 0)
{
//Here adding the bundle image into the imageArray
[imageArray addObject:[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:obj.fileName ofType:#"png" inDirectory:#"Images"]]];
}
else
{
typedef void (^ALAssetsLibraryAssetForURLResultBlock)(ALAsset *asset); typedef void (^ALAssetsLibraryAccessFailureBlock)(NSError *error);
ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *myasset) {
};
ALAssetRepresentation *rep = [myasset defaultRepresentation];
CGImageRef iref = [rep fullResolutionImage];
UIImage *images;
if (iref)
{
//Here adding the photo library image into the imageArray
images = [UIImage imageWithCGImage:iref];
[imageArray addObject:images];
}
else
{
//Here adding the Nofile.png image into the imageArray if didn't find a photo library image
images = [UIImage imageNamed:#"Nofile.png"];
[imageArray addObject:images];
}
ALAssetsLibraryAccessFailureBlock failureblock = ^(NSError *myerror) {
//Here adding the Nofile.png image into the imageArray if any failure occurs
[imageArray addObject:[UIImage imageNamed:#"Nofile.png"]];
NSLog(#"booya, cant get image - %#",[myerror localizedDescription]);
};
NSURL *asseturl = [NSURL URLWithString:obj.fileName];
ALAssetsLibrary* assetslibrary = [[[ALAssetsLibrary alloc] init] autorelease];
[assetslibrary assetForURL:asseturl
resultBlock:resultblock failureBlock:failureblock];
}
}
return imageArray;
}
The problem was when I loads the view at first time the asset library images are not generating, only bundle images were displayed, if i go to any of the another view and return back to 100 image view then the asset images are generated.And works fine. The problem is the same function is not generating asset images at the first load. How can i fix this? Thanks in advance.
All methods related to ALAssetLibrary are asynchronous, so your view may complete its loading life cycle before the desired data is returned. You have to take this into account and redraw your view (or a portion of it) as needed.
My app consists of an image gallery. It is a scroll view which displays pics retrieved from the sqlite db. User can scroll the images, add or delete images etc. I can add a picture to the gallery dynamically. But the problem comes when I need to implement the delete functionality. I use the following code but even after calling removeFromSuperView the image is not getting removed from the scrollview.
-(void)deleteDeck{
if(selectedEditDeck!=0){
[deck deleteSelectedDeck:selectedEditDeck]; //deleting from database
//problem starts here ***
[(UIImageView*)[decksGallery viewWithTag:selectedEditDeck-1]removeFromSuperview];
[self loadGallery];
selectedEditDeck=0;
//Ends here*****
[tableData release];
tableData=[NSMutableArray array];
[self showCardNamesinTable];
[aTableView reloadData];
}
I have already created the uiscrollview in the loadview method. Then to refresh the view after every deletion and addition of images so that I can display the updated gallery, I use the following piece of code:
-(void)loadGallery{ //Reloading all for adding a single deck image.
//Database part****
NSString *sqlStr = [NSString stringWithFormat:#"select first_card from decksTable"];
char *sql = (char*)[sqlStr UTF8String];
kidsFlashCardAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSMutableArray *galleryImagesArray=[appDelegate.dbConnection fetchColumnFromTable:sql col:0];
NSArray *sysPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES);
NSString *docDirectory = [sysPaths objectAtIndex:0];
numberofImages = [galleryImagesArray count];
printf("number is %d",numberofImages);//Database part of code ends here
//In the following fragment of code I add images to UIscrollView
for (int i = 0; i < [galleryImagesArray count]; i++) {
CGFloat yOrigin = i * 65;
NSString *filePath = [NSString stringWithFormat:#"%#/%#", docDirectory,[galleryImagesArray objectAtIndex:i]];
galleryImage = [[UIImageView alloc] initWithFrame:CGRectMake(yOrigin+140, 15,50,50 )];
//galleryImage.tag=[galleryImagesArray count];
galleryImage.tag=i;
printf("THE TAG IS %d",galleryImage.tag);
galleryImage.clipsToBounds=YES;
galleryImage.layer.cornerRadius=11.0;
galleryImage.backgroundColor=[UIColor clearColor];
galleryImage.image =[UIImage imageWithContentsOfFile:filePath];
[decksGallery addSubview:galleryImage];
[galleryImage release];
}
decksGallery.contentSize = CGSizeMake(115*[galleryImagesArray count], 80);
//[decksGallery reloadInputViews];
Make sure your [decksGallery viewWithTag:selectedEditDeck-1] is not returning nil and the image was actually deleted from your db before the refresh code running.
In addition, you are setting imageView.tag = i; in your creation code, since the i would be 0 which is the tag's default value for every UIView, you'd better fix your creation code as well.
If you just want to remove the image from your imageView, you can also do imageView.image = nil;
UIImageView*imageView = (UIImageView*)[decksGallery viewWithTag:selectedEditDeck-1];
[imageView removeFromSuperview];
imageView = nil;
I am not able to add objects to a simple NSMutableArray. I have an objective-c reference next to me and have it working for simple string. But I need to add actual objects. Please tell me what I am doing wrong here.
Code:
TBXMLElement *hubImage = [TBXML childElementNamed:#"image" parentElement:[TBXML childElementNamed:#"images" parentElement:pieceXML]];
if(hubImage) {
do {
HubPieceImage *tmpImage = [[HubPieceImage alloc] initWithXML:hubImage];
[self.images addObject: tmpImage];
HubPieceImage *tmpImage2 = [self.images lastObject];
NSLog(#"image : %#", tmpImage.asset_url);
NSLog(#"image 2: %#", tmpImage2.asset_url);
} while ((hubImage = hubImage->nextSibling));
}
NSLog(#"count : %i", [self.images count]);
Returns this in log as it loops through two objects:
image : http://farm6.static.flickr.com/5215/5533190578_4v629a79e5.jpg
image 2: (null)
image : http://farm3.static.flickr.com/2774/5416668522_fdcr19aed3.jpg
image 2: (null)
count : 0
Actually the array seems to not fill up at all (considering count:0)
Thanks for the help
Just for fun try this:
HubPieceImage *tmpImage = [[HubPieceImage alloc] initWithXML:hubImage];
NSAssert(self.images, #"Whoops! self.images is NULL");
[self.images addObject: tmpImage];
Just might be your problem! That is, self.images might be nil.
I found the problem!
I didn't initialize the array like so:
self.images = [[NSMutableArray alloc] init];
images = [[NSMutableArray alloc] initWithCapacity:10];
Please make sure you have called alloc and init before you