array size different in simulator then on iphone - ios

I have the following code:
NSMutableArray *imageArray = [[NSMutableArray alloc] init];
for(int i = 1; i <= 32; i++) {
//NSString *str = [NSString stringWithFormat:#"marker_%i.png", i];
NSString *str = [NSString stringWithFormat:#"wave%i.png", i];
UIImage *img = [UIImage imageNamed:str];
if(img != nil) {
[imageArray addObject:img];
}
}
NSLog(#"imageArray count %i",[imageArray count]);
NSMutableArray *reverseArray = [NSMutableArray arrayWithArray:imageArray];
[[reverseArray reverseObjectEnumerator] allObjects];
[imageArray addObjectsFromArray:reverseArray];
NSLog(#"imageArray count %i",[imageArray count]);
If i run it on the iphone i get:
2013-05-12 15:21:08.539 RouteApp[5673:907] imageArray count 23
2013-05-12 15:21:08.545 RouteApp[5673:907] imageArray count 46
while if i run in the simulator i get 32 and 64 like i expect.
(like if the numbers are switched)
What can cause this?

It looks like some of the images are missing on the iPhone, so this line
if(img != nil) {
[imageArray addObject:img];
}
filters them out. Change this line as follows to see which images are not present:
if(img != nil) {
[imageArray addObject:img];
} else {
NSLog("Image 'wave%i.png' is missing", i);
}

Filenames on the device are case-sensitive, but are not on the simulator. Some of your image names are likely slightly different from the format you're expecting.
The most common way this happens is something like wave01.png vs. wave01.PNG.
Otherwise it's probably something like wave01.png vs. Wave01.png, etc.

Related

Adding UIImage to NSMutable array for an animation

I have an app that creates an animation from images stored in a group in my project navigator (not Images.xcassets). This code "works" in that it animates properly, but using imageNamed causes a memory leak because the image files are not getting deallocated.
I can't figure out why adding with imageNamed: works adds images to my array, but imageWithContentsOfFile: doesn't.
A little info on the mechanics of my app:
self.myPhoto is set on the segue from another ViewController. The number of images can vary, so I test to see the file is "there" before adding it to the array.
Filenames follow this naming convention:
"1-1.jpg"
"2-1.jpg"
"2-2.jpg"
"99-1.jpg"
"99-2.jpg"
"99-3.jpg"
"99-4.jpg"
This code works, but the images don't deallocate, causing a memory leak:
- (void)startAnimation {
NSMutableArray *imageArray = [[NSMutableArray alloc] init];
for (int imageNumber = 1; self.myPhoto != nil; imageNumber++) {
NSString *fileName = [NSString stringWithFormat:#"%#-%d.jpg", self.myPhoto, imageNumber];
// check if a file exists
if ([UIImage imageNamed:fileName]) {
// if it exists, add it to the array
[imageArray addObject:[UIImage imageNamed:fileName]];
} else {
// otherwise, don't add image to the array
break;
}
}
self.myImageView.animationImages = imageArray;
self.myImageView.animationDuration = 1.5f;
self.myImageView.animationRepeatCount = 0;
self.myImageView.contentMode = UIViewContentModeScaleAspectFit;
[self.myImageView startAnimating];
}
I ran Instruments on it and saw I had a memory leak emanating from my animation. Digging around a little on StackOverflow, I discovered the manner I'm adding my files to myArray results in images not getting deallocated.
So I tried this, instead:
- (void)startAnimation {
NSMutableArray *imageArray = [[NSMutableArray alloc] init];
for (int imageNumber = 1; self.myPhoto != nil; imageNumber++) {
NSString *fileName = [NSString stringWithFormat:#"%#-%d", self.myPhoto, imageNumber];
// check if a file exists
if ([UIImage imageNamed:fileName]) {
// if it exists, add it to the array
[imageArray addObject:[UIImage imageWithContentsOfFile:[[NSBundle mainBundle]pathForResource:[NSString stringWithFormat:#"%#", fileName] ofType:#"jpg"]]];
NSLog(#"%# added to imageArray", fileName);
} else {
// otherwise, don't add image to the array
break;
}
}
NSLog(#"There are %lu images in imageArray", (unsigned long)imageArray.count);
self.myImageView.animationImages = imageArray;
self.myImageView.animationDuration = 1.5f;
self.myImageView.animationRepeatCount = 0;
self.myImageView.contentMode = UIViewContentModeScaleAspectFit;
[self.myImageView startAnimating];
}
When I do it this way, the page where the animation loads appears, but the images don't get added to my array--the . This is a well-documented issue. Here are a few posts covering this problem:
Dirty Memory because of CoreAnimation and CG image
How do I use imageWithContentsOfFile for an array of images used in an animation?
Thank you for reading. I'm stumped, though I'm confident the resolution to this problem is a startlingly stupid oversight on my part. Prove me right ;)
I made some minor changes out of desperation and I stumbled into the "answer". Comments note where I made changes:
- (void)startAnimation {
NSMutableArray *imageArray = [[NSMutableArray alloc] init];
for (int imageNumber = 1; self.myPhoto != nil; imageNumber++) {
// I set the filename here, adding .jpg to it
NSString *fileName = [NSString stringWithFormat:#"%#-%d.jpg", self.myPhoto, imageNumber];
// check if a file exists
if ([UIImage imageNamed:fileName]) {
// if it exists, add it to the array
// I blanked out ofType, as it's set when I create the local fileName variable
[imageArray addObject:[UIImage imageWithContentsOfFile:[[NSBundle mainBundle]pathForResource:[NSString stringWithFormat:#"%#", fileName] ofType:#""]]];
} else {
// otherwise, don't add image to the array
break;
}
}
self.myImageView.animationImages = imageArray;
self.myImageView.animationDuration = 1.5f;
self.myImageView.animationRepeatCount = 0;
self.myImageView.contentMode = UIViewContentModeScaleAspectFit;
[self.myImageView startAnimating];
}

NSDictionary constant looping

SO I have a program which calls the FlickR API, gets the URL's puts them into a dictionary and then assigns them into a table view, using an image view.
NSArray *photos = [self.flickr photosForUser:#"James Kinvig"];
int countAttempts = 0;
[[self.flickr photosForUser:#"James Kinvig"]count];
for (int i = 0; i < [[self.flickr photosForUser:#"James Kinvig"]count]; i++) {
for(NSDictionary *dictionary in photos) {
countAttempts++;
NSString *farmId = [dictionary objectForKey:#"farm"];
NSString *serverId = [dictionary objectForKey:#"server"];
NSString *photoId = [dictionary objectForKey:#"id"];
NSString *secret = [dictionary objectForKey:#"secret"];
self.url= [NSURL URLWithString:[NSString stringWithFormat:#"http://farm%#.staticflickr.com/%#/%#_%#.jpg", farmId, serverId, photoId, secret]];
//NSLog(#"self.url = %#", self.url);
NSLog(#"count = %d", countAttempts);
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
NSData *imgData = [NSData dataWithContentsOfURL:self.url];
dispatch_sync(dispatch_get_main_queue(), ^{
UIImage *img = [UIImage imageWithData:imgData];
cell.imageView.image = img;
[cell setNeedsLayout];
});
});
}
}
return cell;
}
This is the method it calls, photosForUser:
- (NSMutableArray *) photosForUser: (NSString *) friendUserName
{
NSString *request = [NSString stringWithFormat: #"https://api.flickr.com/services/rest/?method=flickr.people.findByUsername&username=%#", friendUserName];
NSDictionary *result = [self fetch: request];
NSString *nsid = [result valueForKeyPath: #"user.nsid"];
request = [NSString stringWithFormat: #"https://api.flickr.com/services/rest/?method=flickr.photos.search&per_page=%ld&has_geo=1&user_id=%#&extras=original_format,tags,description,geo,date_upload,owner_name,place_url", (long) self.maximumResults, nsid];
result = [self fetch: request];
return [result valueForKeyPath: #"photos.photo"];
}
Which does a fetch to the flickr API.
What is happening though is that is stuck in an eternal loop. Even with the for statement being less than the count, it still eternal loops. I have NSLog'd the count of the FlickR photos and it = 11.
This may have something to do with it, but whenever I press the button to take me to the table view controller, I get a HUGE lag, close to a minute, and nothing is being calculated (photo-wise) as I've done a count++
Thanks
let me understand this.. By the last line of your first block of code, I conclude that that is the uitableview dataSource method, cellForRowAtIndexPath.. what doesn't really makes sense.. you you have a fetch there, you have A loop inside a loop, that is setting many images (by download them) in one single imageView, and this is happening for all your visible cells at the same time. This will never work!
The solution is:
1 - remove this method from the cellForRow, this is not the place to request the images
2 - create another method that will fetch the content
3 - create a method that will do your loops and store the images on the array so you don't need to do that many times, only one..
4 - reload the tableview after you finish the step 3
5 - use the array of images that is already done to set your images by indexPath.row in your cell..
6 - I recommend you to use a Library for imageCache (i.e https://github.com/rs/SDWebImage)
NSArray *photos = [self.flickr photosForUser:#"James Kinvig"];
for (int i = 0; i < [[self.flickr photosForUser:#"James Kinvig"] count]; i++)
{
for (NSDictionary *dictionary in photos)
{
You have two nested loops iterating over the same collection. This turns what should be an O(n) operation into O(n^2) and explains why your process is taking a very long time.
Since the loop bodies never use i, I would fix it by getting rid of the outer loop:
NSArray *photos = [self.flickr photosForUser:#"James Kinvig"];
for (NSDictionary *dictionary in photos)
{

display images randomly in 3 UIButton using single array content

I have created three UIButton and i have 11 images in an array. I want to display that images randomly in each and every buttons.
Edited
button2Image, button3Image, button4Image is NSString,
button2Image = [topButtonArray objectAtIndex:l1Counter];
NSArray *reversed = [[testArray reverseObjectEnumerator] allObjects];
button3Image = [topButtonArray objectAtIndex:nextCounter+1];
int random = arc4random_uniform([topButtonArray count]);
button4Image = [topButtonArray objectAtIndex:random];
Note: I don’t want to display same image in each button.
NSArray *urImageArray;//11 images
NSMutableArray *threeImages = [[NSMutableArray alloc]init];
while ([threeImages count]<3) {
id image=[urImageArray objectAtIndex:[self getRandomNumberBetween:0 maxNumber:11-1]];
// Three images must be different
if (![threeImages containsObject:image]) {
[threeImages addObject:image];
}
}
firstButtonImage = [threeImages objectAtIndex:0];
twoButtonImage = [threeImages objectAtIndex:1];
thirdButtonImage = [threeImages objectAtIndex:2];
- (NSInteger)getRandomNumberBetween:(NSInteger)min maxNumber:(NSInteger)max
{
return min + arc4random() % (max - min + 1);
}
If the question is how to pick random elements from array, here is a nice article with examples: http://nshipster.com/random/.
For example:
NSMutableArray *resultArray = [[NSMutableArray alloc] init];
//i is number of required random elements
int i = 3;
while (i-->0)
{
if ([array count] > 0) {
int idx = arc4random_uniform([array count]);
[resultArray addObject:array[idx]];
//array is a mutable array whether the original one or it's deep copy
[array removeObjectAtIndex:idx];
}
}
For that you have to non-repeating random number. Then use that number to get the image from image array
arr123=[[NSMutableArray alloc]init];
int random = arc4random_uniform(11);
[arr123 addObject:[NSString stringWithFormat:#"%d",random]];
[self do1];
NSLog(#"%#",arr123);
int iMatch=0;
-(void)do1
{
int random = arc4random_uniform(11);
if([arr123 count]==2)
return;
for(int i=0;i<1;i++)
{
for(int j=0;j<[arr123 count];j++)
{
if(random==[[arr123 objectAtIndex:j] intValue])
{
iMatch=1;
break;
}
}
if(iMatch==1)
{
iMatch=0;
[self do1];
}
else
{
iMatch=0;
[arr123 addObject:[NSString stringWithFormat:#"%d",random]];
[self do1];
}
}
}
Then use the arr123 array to get the random images from image array using the random indexes
you should create an NSSet with the objects you get from the array. The NSSet has only distinct objects so you will add random objects from the array to the NSSet until the NSSet counts 3 objects. Look at apple NSSet documentation:
https://developer.apple.com/library/mac/documentation/cocoa/Reference/Foundation/Classes/NSSet_Class/Reference/Reference.html

Separate two strings from one array element

I was wondering if anyone could lend some assistance. Basically I am calling a web service and then trying to get the large hosted image url. The output from the web service is so:
images = (
{
hostedLargeUrl = "http://i.yummly.com/Crispy-roasted-chickpeas-_garbanzo-beans_-308444.l.jpg";
hostedSmallUrl = "http://i.yummly.com/Crispy-roasted-chickpeas-_garbanzo-beans_-308444.s.jpg";
}
);
The main problem is that the two strings are in only one of my array elements when I think they should be in 2. Also I'm not 100% but possibly they may be a dictionary :-S I'm just not sure. My code is as follows:
NSArray *imageArray = [[NSArray alloc]init];
imageArray = [self.detailedSearchYummlyRecipeResults objectForKey:#"images"];
NSLog(#"imageArray: %#", imageArray);
NSLog(#"count imageArray: %lu", (unsigned long)[imageArray count]);
NSString *hostedLargeurlString = [imageArray objectAtIndex:0];
NSLog(#"imageArrayString: %#", hostedLargeurlString);
The output (nslog's) from the above code is:
2013-04-28 18:59:52.265 CustomTableView[2635:11303] imageArray: (
{
hostedLargeUrl = "http://i.yummly.com/Crispy-roasted-chickpeas-_garbanzo-beans_-308444.l.jpg";
hostedSmallUrl = "http://i.yummly.com/Crispy-roasted-chickpeas-_garbanzo-beans_-308444.s.jpg";
}
)
2013-04-28 18:59:52.266 CustomTableView[2635:11303] count imageArray: 1
2013-04-28 18:59:52.266 CustomTableView[2635:11303] imageArrayString: {
hostedLargeUrl = "http://i.yummly.com/Crispy-roasted-chickpeas-_garbanzo-beans_-308444.l.jpg";
hostedSmallUrl = "http://i.yummly.com/Crispy-roasted-chickpeas-_garbanzo-beans_-308444.s.jpg";
}
Does anyone have any idea how I can seperate the one element into hostedlargeUrl and hostedsmallUrl respectively?
Any help you can provide is greatly appreciated!
Actually the images array contains a dictionary
images = (
{
hostedLargeUrl = "http://i.yummly.com/Crispy-roasted-chickpeas-_garbanzo-beans_-308444.l.jpg";
hostedSmallUrl = "http://i.yummly.com/Crispy-roasted-chickpeas-_garbanzo-beans_-308444.s.jpg";
}
);
so :
NSDictionary *d = [self.detailedSearchYummlyRecipeResults objectForKey:#"images"][0];
NSString *largeURL = d[#"hostedLargeUrl"];
NSString *smallURL = d[#"hostedSmallUrl"];
The value of [imageArray objectAtIndex:0] is a NSDictionary. You've incorrectly specified it as a NSString. You need the following:
NSDictionary *hostedLarguerDictionary =
(NSDictionary *) [imageArray objectAtIndex:0];
and then to access the 'large url' use:
hostedLarguerDictionary[#"hostedLargeUrl"]
or, equivalently
[hostedLarguerDictionary objectForKey: #"hostedLargeUrl"];
looks like an array with in an array so
NSArray* links = [self.detailedSearchYummlyRecipeResults objectForKey:#"images"];
NSString* bigLink = [links objectAtIndex:0];
NSString* smallLink = [links objectAtIndex:1];
or it could be a dictionary
NSDictionary* links = [self.detailedSearchYummlyRecipeResults objectForKey:#"images"];
NSString* bigLink = [links objectForKey:#"hostedLargeUrl "];
NSString* smallLink = [links objectForKey:#"hostedSmallUrl "];
you can see the class of the object by printing out the class name
NSLog(#"Class Type: %#", [[self.detailedSearchYummlyRecipeResults objectForKey:#"images"] class]);

Only some png images display, others don't for no apparent reason

I have some code which randomly displays a given .png image and its title.The title logic is working fine. However, for some reason, only two of the four images display. I've tried changing the order just in case, but only those two images, pic_c and pic_d, ever get displayed. I've also checked the spelling, and that the files are in resources and exist on the file system. Here's the code which displays the image:
NSMutableArray *fileNameArray = [[NSMutableArray alloc] init];
[fileNameArray addObject:[NSString stringWithFormat: #"pic_a"]];
[fileNameArray addObject:[NSString stringWithFormat: #"pic_b"]];
[fileNameArray addObject:[NSString stringWithFormat: #"pic_c"]];
[fileNameArray addObject:[NSString stringWithFormat: #"pic_d"]];
NSMutableArray *titleArray = [[NSMutableArray alloc] init];
[titleArray addObject:[NSString stringWithFormat: #"pic a"]];
[titleArray addObject:[NSString stringWithFormat: #"pic b"]];
[titleArray addObject:[NSString stringWithFormat: #"pic c"]];
[titleArray addObject:[NSString stringWithFormat: #"pic d"]];
int index = arc4random() % [fileNameArray count];
NSString *pictureName = [titleArray objectAtIndex:index];
art_title.text = pictureName;
NSString* imagePath = [ [ NSBundle mainBundle] pathForResource:pictureName ofType:#"png"];
UIImage *img = [ UIImage imageWithContentsOfFile: imagePath];
if (img != nil) { // Image was loaded successfully.
[imageView setImage:img];
[imageView setUserInteractionEnabled:NO];
[img release]; // Release the image now that we have a UIImageView that contains it.
}
[super viewDidLoad];
[fileNameArray release];
[titleArray release];
}
Any idea why this might be happening?
Recent information: If I remove the titleArray, and use the file name array only, all the images show up. However, I'd still like to be able to use the titleArray.
What are your image files actually called? In the code above you don't actually do anything with finleNameArray except count it. You use the values from titleArray to get the image resource. I would think you need the following code in there:
NSString *filename = [fileNameArray objectAtIndex:index];
Then change your imagePath to use this instead of pictureName.

Resources