I have got this code which creates an image:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
background = [[UIImageView alloc]initWithFrame:CGRectMake(150, 60, 180, 180)];
result = [[UIImageView alloc]initWithFrame:CGRectMake(150, 60, 180, 180)];
[background setImage:[UIImage imageNamed:[defaults objectForKey:#"colour"]]];
[self.view addSubview:background];
[self.view insertSubview:result aboveSubview:background];
This is in my viewWillAppear. When I press a button, this happens:
- (IBAction)oneToSix {
int rNumber = (arc4random() % 6) + 1;
[result setImage:[UIImage imageNamed:[NSString stringWithFormat:#"%#", rNumber]]];
}
But it gets this fatal error: Thread one: Program received signal: "EXC_BAD_ACCESS". on the setImage part when I press the button. What is the problem? I am new to Objective C.
I think the problem is string format in NSString, you should change the code to :
[result setImage:[UIImage imageNamed:[NSString stringWithFormat:#"%d", rNumber]]];
as rNumber is an int.
And you should release the background and result, as viewWillAppear will tend to be called every time the view is appear so will result a memory leak.
Related
I have an UIWebView page with one UIScrollView, inside of my UIScrollView I have UIImage and buttons
I want to set specific title for each button from my xml file, Would you please give me some hint for implementing this?
rightnow I can get the first name from xml but it"s set for all
my scrollView with Button and images:
const NSUInteger kNumImages = 5;
scrollView1.pagingEnabled = YES;
// load all the images
NSUInteger i;
for (i = 1; i<= kNumImages; i++)
{
NSString *imageName = [NSString stringWithFormat:#"image%d.jpg", i];
UIImage *image = [UIImage imageNamed:imageName];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
imageView.userInteractionEnabled = YES;
CGRect rect = imageView.frame;
rect.size.height = kScrollObjHeight;
rect.size.width = kScrollObjWidth;
imageView.frame = rect;
imageView.tag = i;
[scrollView1 addSubview:imageView];
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
appDelegate = (testAppDelegate *)[[UIApplication sharedApplication] delegate];
Presentation1Name *aSlide = [appDelegate.books objectAtIndex:0];
NSLog(#" %#", aSlide.slideLabel );
[btn setTitle:[NSString stringWithString:aSlide.slideLabel]
forState:UIControlStateNormal];
btn.frame = rect;
[btn setTag:i];
[btn addTarget:self action:#selector(buttonClick:)
forControlEvents:UIControlEventTouchUpInside];
[imageView addSubview:btn];
}
[self layoutScrollImages];
}
for adding title for all button I'm using code
[btn setTitle:[NSString stringWithString:aSlide.slideLabel]
forState:UIControlStateNormal];
but for each button I want to have specific title from xml file
Thanks in advance!
Here is my xml file:
<Presentation label="presentation1">
<slides>
<slide index="0" label="slide1" identifier="Slide1Name" />
<slide index="1" label="something" identifier="Slide2Name" />
</slides>
</Presentation>
Edit:
When I add Presentation1Name *aSlide = [appDelegate.books objectAtIndex:0]; objectAtIndex to i I will get this error
when I add objectAtIndex: i
process terminated * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: ' -[NSPlaceholderString initWithString:]: nil argument'
** First throw call stack:
(0x1c95012 0x10d2e7e 0x1c94deb 0xae97f5 0xae9774 0x3d64 0x4723 0x10e6705 0x1d920 0x1d8b8 0xde671 0xdebcf 0xddd38 0x4d33f 0x4d552 0x2b3aa 0x1ccf8 0x1bf0df9 0x1bf0ad0 0x1c0abf5 0x1c0a962 0x1c3bbb6 0x1c3af44 0x1c3ae1b 0x1bef7e3 0x1bef668 0x1a65c 0x295d 0x2885 0x1)
libc++abi.dylib: terminate called throwing an exception
(lldb)
and it"s because of
-[NSPlaceholderString initWithString:]: nil argument'
after that I change 5 t0 2 since I have just 2 label in my xml file
const NSUInteger kNumImages= 2;
and also change for (i = 1; i<= kNumImages; i++) to
for (i = 0; i> kNumImages; i++)
but still it"not working correctly
My question is How can I do this
appDelegate.books count should be equal to kNumImages
[btn setTitle:[NSString stringWithFormat:#"MyButton %d", i] forState:UIControlStateNormal];
Store all button names in NSMutableArray and then later use it
For example like this:
NSMutableArray *arrNames = [NSMutableArray alloc]initWithObjects:#"Dog",#"Cat",......,nil]; //fill your array
[btn setTitle:[arrNames objectAtIndex:i] forState:UIControlStateNormal];
Second option is to use #Andrey Chernukha justed in his answer
Hello I am new to animations and just started playing around with it recently. I want to have a circle (ring) displayed that goes from a small ring to a large ring, dissapears and then does the process all over again except in a different location.
To do this I have created 6 different image sizes of the same ring. The following code is how I have done it but I do not know how to repeat the process (AkA it runs the method but the location of the ring stays the same, I need to loop the random number generator but don't know when to do a check if the image has stopped). If this is not the right way to go about this, please let me know! P.S. The ring looks very ugly by the time it gets to its largest stage, not sure why.
Thanks
-(void) doWork
{
NSInteger number;
NSInteger number2;
NSLog (#"here");
number = (arc4random()%100)+1;
number2 = (arc4random()%100)+1;
NSLog (#" hello numer1: %d", number);
NSLog (#" hello numer2: %d", number2);
imageView = [[UIImageView alloc] initWithFrame:CGRectMake(number, number2, 135, 135)];
imageView.animationImages= [NSArray arrayWithObjects:
[UIImage imageNamed:#"smallestRing.png"],
[UIImage imageNamed:#"smallRing.png"],
[UIImage imageNamed:#"mediumRing.png"],
[UIImage imageNamed:#"large2Ring.png"],
[UIImage imageNamed:#"largeRing.png"], nil];
imageView.animationDuration= 2.5;
imageView.animationRepeatCount= 0;
imageView.contentMode = UIViewContentModeScaleAspectFit;
[imageView startAnimating];
[self.view addSubview:imageView];
/*[NSTimer scheduledTimerWithTimeInterval:5 target:self selector:#selector(doWork) userInfo:nil repeats:YES];*/
}
if resizing (or other transforming such as rotation or transition) is the only animation you need, you could use method +animateWithDuration (you can found description here)
it will look like:
-(void) doWork
{
NSInteger number;
NSInteger number2;
NSLog (#"here");
number = (arc4random()%100)+1;
number2 = (arc4random()%100)+1;
NSLog (#" hello numer1: %d", number);
NSLog (#" hello numer2: %d", number2);
imageView = [[UIImageView alloc] initWithFrame:CGRectMake(number, number2, 135, 135)];
imageView.image = [UIImage imageNamed:#"largeRing.png"];
[self.view addSubview:imageView];
[self animate:imageView enlarge:YES];
}
-(void) animate:(UIImageView*)imageView enlarge:(BOOL)flag
{
if (flag)
{
// then animating is starting
// and imageView will appear in random point of view
int randomX = arc4random()%self.view.frame.size.width;
int randomY = arc4random()%self.view.frame.size.height;
imageView.center = CGPointMake(randomX, randomY);
}
double scale = flag ? 2 : 0.5;
[UIView animateWithDuration:5
animations:^{ imageView.transform = CGAffineTransformMakeScale(scale,scale); }
completion:^(BOOL finished){ [self animate:imageView: enlarge:!flag]; }];
}
You can query the bool isAnimating in order to determine if the animation of the UIImageView ended
P.S:
Probably it looks ugly because of
imageView.contentMode = UIViewContentModeScaleAspectFit;
Try something like
imageView.contentMode = UIViewContentModeCenter;
Final solution to this issue is given below the question
My goal is to create an image picker that initially creates each image view inside of a scroll view, and then passes a reference for that image view to a method that will asynchronously update the imageview.image with the appropriate image.
This works great as is.
The issue I run into is that the scroll view only shows the image views in a batch at the end of the method, whereas I'd like for them to print one by one as they are created (image available or not).
If I touch the scroll view to scroll, it works the way I want it to, but if I make no touch at all, the screen stays white until all of the images, not just image views, have finished loading.
I've tried placing setNeedsDisplay everywhere, for every view, including self.view, scrollview, and each individual imageview. What's going on?
- (void)viewDidLoad {
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
[self setGridView];
});
}
- (void)setGridView {
// begin loading images
NSString * retina = ([[MVProject sharedInstance] settings_retina]) ? #"2" : #"";
CGRect scrollframe = CGRectMake(0, 0, 300, 275);
UIScrollView * newscrollview;
newscrollview = [[UIScrollView alloc] initWithFrame:scrollframe];
newscrollview.scrollEnabled = YES;
newscrollview.delegate = self;
[newscrollview setContentSize:CGSizeMake(300, (((ceilf([[NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:#"Flickr_Dictionary"]] count]/4)) * (58+15)) + 15 + 58 + 15))];
[picsMVContentCell.contentView addSubview:newscrollview];
float currentx = 11;
float currenty = 17;
NSInteger index = 0;
for (NSDictionary * d in [NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:#"Flickr_Dictionary"]]) {
// create button
UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(currentx, currenty, 58, 58);
button.imageView.backgroundColor = [UIColor colorWithRed:(241/255.0) green:(241/255.0) blue:(241/255.0) alpha:1];
button.imageView.contentMode = UIViewContentModeScaleAspectFit;
button.imageView.layer.cornerRadius = 6;
button.imageView.layer.masksToBounds = YES;
button.imageView.accessibilityLabel = [d objectForKey:#"id"];
button.imageView.accessibilityValue = [d objectForKey:#"full"];
button.imageView.tag = index++;
[button addTarget:self action:#selector(imageClick:) forControlEvents:UIControlEventTouchUpInside];
UIImage * image = [MVImage imageWithImage:[UIImage imageNamed:#""] covertToWidth:58.0f covertToHeight:58.0f];
[button setImage:image forState:UIControlStateNormal];
[newscrollview addSubview:button];
[newscrollview bringSubviewToFront:button];
[newscrollview setNeedsDisplay];
// calculate next image view position
currentx += (button.imageView.frame.size.width+15);
if (currentx >= 289) {
currentx = 11;
currenty += (button.imageView.frame.size.height+15);
}
// set image
NSString * nsuserdefault = [NSString stringWithFormat:#"Settings_SFThumbs%#_%#", retina, [d objectForKey:#"id"]];
if ([NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:nsuserdefault]]) {
MVImage * thumb = [NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:nsuserdefault]];
[button setImage:[MVImage imageWithImage:[[UIImage alloc] initWithData:thumb.data] covertToWidth:58.0f covertToHeight:58.0f] forState:UIControlStateNormal];
} else {
[MVProject asynchronousImageLoad:button.imageView urlpath:[d objectForKey:#"thumb"] nsuserdefaultpath:nsuserdefault];
}
}
}
Edit on Feb 7, 2012 3:26 PM
these changes fixed all issues related to the code given in the question
thanks to #Eugene for pointing me in the right direction
/* ---------- ---------- ---------- ---------- ---------- */
- (void)viewDidLoad {
[super viewDidLoad];
[[MVProject sharedInstance] syncLoadSF:0];
self.newscrollview = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 300, 275)];
self.newscrollview.scrollEnabled = YES;
self.newscrollview.delegate = self;
[self.newscrollview setContentSize:CGSizeMake(300, (((ceilf(([[NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:#"Flickr_Dictionary"]] count]-1)/4)) * (58+15)) + 15 + 58 + 15))];
[picsMVContentCell.contentView addSubview:self.newscrollview];
[self setGridView];
}
/* ---------- ---------- ---------- ---------- ---------- */
- (void)setGridView {
NSString * retina = ([[MVProject sharedInstance] settings_retina]) ? #"2" : #"";
[self.newscrollview setNeedsDisplay];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
NSInteger index = 0;
for (NSDictionary * d in [NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:#"Flickr_Dictionary"]]) {
// create button
UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake((11 + ((index%4)*(58+15))), (17 + ((floorf(index/4))*(58+15))), 58, 58);
button.imageView.backgroundColor = [UIColor colorWithRed:(241/255.0) green:(241/255.0) blue:(241/255.0) alpha:1];
button.imageView.contentMode = UIViewContentModeScaleAspectFit;
button.imageView.layer.cornerRadius = 3;
button.imageView.layer.masksToBounds = YES;
button.imageView.accessibilityLabel = [d objectForKey:#"id"];
button.imageView.accessibilityValue = [d objectForKey:#"full"];
button.imageView.tag = index++;
[button addTarget:self action:#selector(imageClick:) forControlEvents:UIControlEventTouchUpInside];
dispatch_sync(dispatch_get_main_queue(), ^ {
[button setImage:[MVImage imageWithImage:[UIImage imageNamed:#""] covertToWidth:58.0f covertToHeight:58.0f] forState:UIControlStateNormal];
[self.newscrollview addSubview:button];
[self.newscrollview bringSubviewToFront:button];
[self.newscrollview setNeedsDisplay];
// set image
NSString * nsuserdefault = [NSString stringWithFormat:#"Settings_SFThumbs%#_%#", retina, [d objectForKey:#"id"]];
if ([NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:nsuserdefault]]) {
MVImage * thumb = [NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:nsuserdefault]];
[button setImage:[MVImage imageWithImage:[[UIImage alloc] initWithData:thumb.data] covertToWidth:58.0f covertToHeight:58.0f] forState:UIControlStateNormal];
} else {
[MVProject asynchronousImageLoad:button.imageView urlpath:[d objectForKey:#"thumb"] nsuserdefaultpath:nsuserdefault];
}
});
}
});
[self.newscrollview setNeedsDisplay];
}
You cannot work with drawing on the background thread. Each time you add subview you should do this in the main thread. So the salvation for you would be to use your drawing code in a sync block, that's run on the main queue
dispatch_sync(dispatch_get_main_queue(), ^ {
[newscrollview addSubview:button];
[newscrollview bringSubviewToFront:button];
[newscrollview setNeedsDisplay];
// calculate next image view position
currentx += (button.imageView.frame.size.width+15);
if (currentx >= 289) {
currentx = 11;
currenty += (button.imageView.frame.size.height+15);
}
// set image
NSString * nsuserdefault = [NSString stringWithFormat:#"Settings_SFThumbs%#_%#", retina, [d objectForKey:#"id"]];
if ([NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:nsuserdefault]]) {
MVImage * thumb = [NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:nsuserdefault]];
[button setImage:[MVImage imageWithImage:[[UIImage alloc] initWithData:thumb.data] covertToWidth:58.0f covertToHeight:58.0f] forState:UIControlStateNormal];
} else {
[MVProject asynchronousImageLoad:button.imageView urlpath:[d objectForKey:#"thumb"] nsuserdefaultpath:nsuserdefault];
}
});
The problem your having is with setting the images. What your trying to do is add all the image containers to the scrollview. Then as the images are ready load them into their container. There are 2 ways to go about doing this.
First off add all the containers to the scrollview. (You might want some loading indicator or default image to show its loading)
1) Create a background thread for getting the images ready. When the image is ready add it to its container. (I find this way to be more work and kinda a pain)
2) Create a custom container, and let the custom container add its own image when its image is ready.
For example, I am loading images from a server. So I created AsyncImage class that is a custom class of UIImageView. And I created a function that I send the image url to and it handles the rest. It creates an NSURLConnection and when the data is loaded it calls self.image = [UIImage imageWithData:data];
I have created two UIImageViews in my code:
UIImageView *background = [[UIImageView alloc]initWithFrame:CGRectMake(150, 60, 180, 180)];
UIImageView *result = [[UIImageView alloc]initWithFrame:CGRectMake(150, 60, 180, 180)];
[self.view addSubview:background];
[self.view addSubview:result];
[self.view insertSubview:result aboveSubview:background];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[background setImage:[UIImage imageNamed:[defaults objectForKey:#"colour"]]];
When you press a button, this code is executed:
- (IBAction)oneToSix {
int rNumber = (arc4random() % 6) + 1;
[result setImage:[UIImage imageNamed:[NSString stringWithFormat:#"%d", rNumber, #".png"]]];
}
but the image doesn't change.
Also, I am getting these errors:
You are redeclaring variables in the method scope that were already defined at the class scope. Remove the UIImageView * part from your initialization.
Note: it's doing nothing when you change image, because in ObjectiveC, a method call to nil (uninitialized instance member) is valid, and produces no visible result.
[result setImage:[UIImage imageNamed:[NSString stringWithFormat:#"%d", rNumber, #".png"]]];
Note you are only putting the number into that string. You'll want %d%# as the format.
Those aren't errors, they are warnings. You have an instance variable in your class called background. You also declare a local variable called background in your method. The warning is to let you know that there's a conflict and that it's choosing the local variable over the instance variable.
Is the image named Red or Red.png? Because if it is the latter, you should append the file extension in the setImage method with something like [NSString stringWithFormat:#"%#.png", [defaults objectForKey:"colour"]]
Also, you are inserting the result imageView twice. Remove the first one.
I have several buttons on my app that are being created dynamically. They are all pointed at the button click event when pressed. When the button pressed method is called, the sender's tag (int value) is parsed into the controller's house ID. It works with one of the buttons — the first one created, to be specific — but the others throw the following error:
-[CFNumber intValue]: message sent to deallocated instance 0xc4bb0ff0
I am not releasing these buttons anywhere in my code. I haven't set them to autorelease or anything like that. I'm just wondering why they are doing this on the click.
The button click event:
- (IBAction) ButtonClick: (id) sender
{
HouseholdViewController *controller = [[HouseholdViewController alloc] initWithNibName:#"HouseholdViewController" bundle:nil];
controller.delegate = self;
controller.HouseID = [(NSInteger)[(UIButton *)sender tag] intValue]; //this line throws an error
controller.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:controller animated:YES];
[controller release];
}
Where I am creating the buttons:
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(MyLongInScreenCoords, MyLatInScreenCoords, 50, 50);
UIImage *buttonImageNormal = [UIImage imageNamed:#"blue_pin.png"];
UIImage *strechableButtonImageNormal = [buttonImageNormal stretchableImageWithLeftCapWidth:50 topCapHeight:50];
[button setBackgroundImage:strechableButtonImageNormal forState:UIControlStateNormal];
[self.view addSubview:button];
button.tag = [NSNumber numberWithInt:[[words objectAtIndex: i] intValue]];
ButtonPoints[CurrentHouseCount][0] = button;
ButtonPoints[CurrentHouseCount][1] = [NSValue valueWithCGPoint:CGPointMake(MyActualLat, MyActualLong)];
[button addTarget:self action:#selector(ButtonClick:) forControlEvents:UIControlEventTouchUpInside];
CurrentHouseCount++;
tag is an integer property, not an object. just set it
button.tag = [[words objectAtIndex: i] intValue];
and use:
controller.HouseID = [(UIButton *)sender tag];