I have the following code:
#interface NeighborProfileViewController : UIViewController {
UIImageView * profPic;
UITextView * text;
UIButton * buzz;
NSString * uid;
NSMutableData *responseData;
NSDictionary * results;
}
#property (nonatomic, retain) IBOutlet UIImageView * profPic;
#property (nonatomic, retain) IBOutlet UITextView * text;
#property (nonatomic, retain) IBOutlet UIButton * buzz;
#property (nonatomic, retain) NSString * uid;
#end
Here's what I have in the viewDidLoad on the .m file
#implementation NeighborProfileViewController
#synthesize uid;
#synthesize profPic;
#synthesize buzz;
#synthesize text;
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
NSURL *url = //some URL to the picture;
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *img = [[[UIImage alloc] initWithData:data] autorelease];
self.profPic = [[UIImageView alloc] initWithImage: img];
}
I think I wired up the UIImageView via IB correctly. I have an outlet from the UIImageView to the profPic in the Files Owner. What am I doing wrong?
If you are setting a default image is that staying visible after you call self.profPic = [UIImageView] or is it being removed from the screen?
I think this problem comes when self.profPic releases the old image view to replace it with the one you've just created. The old UIImageView instance, along with all the properties which you defined in IB, are probably automatically removed from the superview. Which is why you're not seeing the downloaded image.
If you used IB to create the UIImageView then you don't want to create a new ImageView and assign it to profPic (which is already a fully instantiated UIImageView). Try calling [profPic setImage:img]; which will just change the image in the profPic imageview.
#Equinox use
[profPic setImage:img];
instead of
self.profPic = [[UIImageView alloc] initWithImage: img];
although using autorelease is not an issue here.
you can also do something like this
UIImage *img = [[UIImage alloc] initWithData:data] ;
[profPic setImage:img];
[img release];
the problem with
self.profPic = [[UIImageView alloc] initWithImage: img];
is that you are now creating another memory location for profPic and that means profPic will no longer point to the UIImageView in your IB any more
Related
I'm trying to displaying an image from file on my ViewController in Xcode. I have in my ViewController.h:
UIImageView *image;
#property(nonatomic,retain) IBOutlet UIImage* image ;
ViewController.m
- (id)initWithImage:(UIImage *)image
{
UIImageView * imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"nameoffile.jpg"]];
self.image = image;
[image release];
}
But no luck. It won't let me link my UIImage instance in the xib.
Try to use this one.You know you can't get IBOutlet on UIImage. So you need to write UIImageView instead of UIImage.
#property(nonatomic,retain) IBOutlet UIImageView* image ;
As the UIImageView is created when the NIB file is loaded, there is no need to make it an instance variable, so remove it from your header file:
UIImageView *image;
Next ensure that your UIImageView outlet is actually connected correctly to the image view within the NIB file. You will see a filled circle when it is connected (this is from a Beginning iOS Development example, which uses ARC, so ignore the weak keyword):
And finally you should be able to set the image view's image in the viewDidLoad method (there is no need to use an instance variable for the UIImage either, as it will be retained within the UIImageView):
- (void)viewDidLoad
{
[super viewDidLoad];
imageView.image = [UIImage imageNamed:#"nameoffile.jpg"];
}
Check the Error of your code.
#property(nonatomic,retain) UIImageView *imageView;
#property(nonatomic,retain)UIImage* image ;
- (id)initWithImage:(UIImage *)image
{
_imageView = [[UIImageView alloc] initWithImage:image];
_imageView.frame=self.view.frame;
[self.view addSubView:_imageView];
[image release];
}
I've written some code to make a screenshot of the view. I write that image to the photo library. But the thing is, I want to use that image in an other imageView in another ViewController. How can I save the image somewhere in the app and use it in another ViewController?
My code:
UIView* captureView = self.view;
UIGraphicsBeginImageContextWithOptions(captureView.bounds.size, captureView.opaque, 0.0);
[captureView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * screenshot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
CGRect cropRect = CGRectMake(0 ,0 ,640,1136);
UIGraphicsBeginImageContextWithOptions(cropRect.size, captureView.opaque, 1.0f);
[screenshot drawInRect:cropRect];
UIImage * customScreenShot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageWriteToSavedPhotosAlbum(customScreenShot , nil, nil, nil);
You first need to save your image on the disk:
NSString *documentDirectory =
[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)
objectAtIndex:0];
NSString *pngFilePath = [NSString stringWithFormat:#"%#/myImage.png",documentDirectory];
NSData *imageData = [NSData dataWithData:UIImagePNGRepresentation(customScreenShot)];
[imageData writeToFile:pngFilePath atomically:YES];
And then you can create an UIImageView with the file:
UIImageView *myImageView = [[UIImageView alloc] initWithImage:[UIImage
imageWithContentsOfFile:pngFilePath]];
[self.view addSubview:myImageView];
If you are using Storyboards, you could pass it to the next view controller like so; in the prepareForSegue method ( this relieves you from having to save it to disk ):
Note: the name of the segue is set by you in MainStoryboard.storyboard. - mySegue.
kMySegue is just a key for that. i.e. #define kMySegue #"mySegue"
imageInOtherViewController is a UIImage in the other view controller.
// TheFirstViewController.m
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
id destinationViewController = [segue destinationViewController];
if ([[segue identifier] isEqualToString:kMySegue]){
if ([destinationViewController respondsToSelector:#selector(setImageInOtherViewController:)]){
[destinationViewController setImageInOtherViewController:[UIImage imageNamed:#"myImage.png"]];
FastCameraViewController *viewController = segue.destinationViewController;
viewController.delegate = self;
}
}
// OtherViewController.h
#interface OtherViewController : UIViewController
{
}
#property (nonatomic, strong) IBOutlet UIImageView *otherViewControllerImageView;
#property (nonatomic, strong) UIImage *imageInOtherViewController;
// OtherViewController.m
#implementation OtherViewController
#synthesize otherViewControllerImageView;
#synthesize imageInOtherViewController;
- (void)viewDidLoad{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[[self otherViewControllerImageView] setImage:imageInOtherViewController];
}
To cache your images I recommend using the NSCache class first ie
NSCache* imagesCache = [[NSCache alloc] init];
[imagesCache setName:#"imagesCache"];
[imagesCache setObject:customScreenShot forKey:#"image1"];
the good news is that NSCache accepts any object of type id so you can store images, mp3s, whatever you want.
If you would like to use the phone's file directory (which is more expensive to use than NSCache..) I recommend you use the Library/Caches directory instead of the Documents directory.. so building on iDevzilla's answer:
NSString *documentDirectory =
[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)
objectAtIndex:0];
I have three ways of writing this code. The third way confuses me.
First way works fine.
//.h
#property (weak, nonatomic) IBOutlet UIImageView *picImageStage;
//.m
NSString *name = [NSString stringWithFormat:#"allen.png"];
UIImage *image = [UIImage imageNamed:name];
UIImageView *t = [[UIImageView alloc]initWithImage:image];
self.picImageStage = t;
Second way works fine.
//.h
#property (retain, nonatomic) IBOutlet UIImageView *picImageStage;
//.m
NSString *name = [NSString stringWithFormat:#"allen.png"];
UIImage *image = [UIImage imageNamed:name];
self.picImageStage = [[UIImageView alloc]initWithImage:image];
Third way turns wrong.
//.h
#property (weak, nonatomic) IBOutlet UIImageView *picImageStage;
//.m
NSString *name = [NSString stringWithFormat:#"allen.png"];
UIImage *image = [UIImage imageNamed:name];
self.picImageStage = [[UIImageView alloc]initWithImage:image];
I don’t understand the reason. Could anyone help me? Thanks :D
In the 3rd snippet you have declared the #property as weak, and the UIImageView will be deallocated immediately. Because a weak relationship will be nil'd when there is no strong relationship to the same object.
In the 1st snippet, which is almost the same, you assigned the UIImageView to a local variable first. This local variable uses a strong relationship implicitly. If you leave the scope of the local strong variable (i.e. the method where you run this code) the property will be deallocated too, except if you create another strong assignment before leaving the scope of the variable. Which will for example happen if you add the UIImageView as a subView of another view. Adding a view to another creates a strong relationship.
Let's examine all three, because that might be the easiest way to explain this to you.
Number 1
//first method
//.h
#property (weak, nonatomic) IBOutlet UIImageView *picImageStage;
//.m
NSString *name = [NSString stringWithFormat:#"allen.png"];
UIImage *image = [UIImage imageNamed:name];
UIImageView *t = [[UIImageView alloc]initWithImage:image];
self.picImageStage = t;
You're initializing a local variable UIImageView with a retain count of +1. Because weak properties don't call implicit retains on their values, you don't own the value stored in self.picImageStage, which means you're one lucky camper because as soon as the function that declares that local UIImageView passes out of scope, your variable is deallocated.
Number 2
//second method
//.h
#property (retain, nonatomic) IBOutlet UIImageView *picImageStage;
//.m
NSString *name = [NSString stringWithFormat:#"allen.png"];
UIImage *image = [UIImage imageNamed:name];
self.picImageStage = [[UIImageView alloc]initWithImage:image];
This one gets into those implicit retains I was talking about. The compiler expands this line:
self.picImageStage = [[UIImageView alloc]initWithImage:image];
out to
self.picImageStage = [[[UIImageView alloc]initWithImage:image]retain];
Meaning that you own it, and are free to do with it what you please.
Number 3
//third method
//.h
#property (weak, nonatomic) IBOutlet UIImageView *picImageStage;
//.m
NSString *name = [NSString stringWithFormat:#"allen.png"];
UIImage *image = [UIImage imageNamed:name];
self.picImageStage = [[UIImageView alloc]initWithImage:image];
Not only are you assigning to a weak property from a variable that you don't own, as soon as the assignment is called, your variable won't store the value! It's because, again, weak pointers do not call implicit retains on their assignments, meaning you have no control over how long the variable sticks around, and I'm willing to bet that it doesn't stay alive for very long!
Here you use weak property instead of retain and also alloc it directly with UIImage...
Also in first stage when you assign UIImageView to the picImageStage then its work fine because its directly equal and store in the picImageStage.. thats the difference..
if you use
#property (retain, nonatomic) IBOutlet UIImageView *picImageStage;
instead of
#property (weak, nonatomic) IBOutlet UIImageView *picImageStage;
then its work fine with this reason..
Just try this
//.h
#property (weak, nonatomic) IBOutlet UIImageView *picImageStage;
//.m
NSString *userName = #"allen";
NSString *imgName = [NSString stringWithFormat:#"%#.png",userName];
UIImage *image = [UIImage imageNamed:imgName];
[self.picImageStage setImage:image];
I am currently dynamically adding a UIImage to my UIScrollView object and everything is working as intended. I need to add extra functionality now (a UIActivityIndicator in the center of the image when it is loading from the internet, and a label underneath) so I thought why not create a custom View which has all of these laid out as I need them to be, and then just load it into the scrollView. I have encountered a problem though, when I add it to the scrollView, nothing shows up. Here is what I have:
NewsViewController.m:
imageScrollView.contentSize = CGSizeMake(320*numberOfPages, 303);
pageControl.numberOfPages = numberOfPages;
dispatch_queue_t imageDownload = dispatch_queue_create("imageDownload", NULL);
__block NSData *temp;
CustomImageView *customImageView = [[CustomImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 303)];
[imageScrollView addSubview:customImageView];
[[customImageView activityIndicator] startAnimating];
dispatch_async(imageDownload, ^{
temp = [[NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://www.wlfarm.org/wp-content/uploads/2012/05/farm.jpg"]]retain];
dispatch_async(dispatch_get_main_queue(), ^{
customImageView.imageView.image = [[UIImage alloc] initWithData:temp];
[[customImageView activityIndicator] stopAnimating];
[customImageView setNeedsDisplay];
customImageView.caption.text = #"HAHAHAHAHHAHA";
[imageScrollView setNeedsDisplay];
[temp release];
});
});
dispatch_release(imageDownload);
CustomImageView.h:
#import <UIKit/UIKit.h>
#interface CustomImageView : UIView
{
IBOutlet UIImageView *imageView;
IBOutlet UILabel *caption;
IBOutlet UIActivityIndicatorView *activityIndicator;
}
#property (nonatomic, retain) IBOutlet UIImageView *imageView;
#property (nonatomic, retain) IBOutlet UILabel *caption;
#property (nonatomic, retain) IBOutlet UIActivityIndicatorView *activityIndicator;
#end
CustomImageView.m
#import "CustomImageView.h"
#interface CustomImageView ()
#end
#implementation CustomImageView
#synthesize caption, imageView, activityIndicator;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
I am including a screenshot of my XIB file, and the program running on the simulator. The first picture shows nothing in the scrollView(the attempt made by using my custom class), and the second page of the scroll view is the attempt made by adding a UIImageView to the UIScrollView(which worked). Can anyone point out what I am doing wrong? Am I not allowed to load a custom view into a UIScrollView? Thanks for your help!
IB Screenshot - http://i.stack.imgur.com/gz9UL.png
iOS Simulator No Image with CustomView Screenshot - http://i.stack.imgur.com/zhswq.png
iOS Simulator Image with UIImageView Screenshot - http://i.stack.imgur.com/97vmU.png
It looks as though CustomImageView is a subclass on UIViewController, not UIImageView or UIView. You can't add a UIViewController as a subview like that. change it to subclass UIView and it should work.
To load a UIView from a .nib, you need to declare your IBOutlet properties as you would for a UIViewController. Define the correct custom class in IB and connect everything up, including the base view. Then override the following method inside your custom view class.
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// Initialization code.
//
[[NSBundle mainBundle] loadNibNamed:#"<NIB NAME HERE>" owner:self options:nil];
[self addSubview:self.view];
}
return self;
}
It seems you have cut and pasted methods from a UIViewController subclass into you UIView subclass. Start by deleting all the methods you've pasted in between #synthesize and #end . A UIView subclass requires different methods to to load from a .nib, so you need to override the method shown above instead and use the line of code
[[NSBundle mainBundle] loadNibNamed:#"<NIB NAME HERE>" owner:self options:nil];
to load the nib.
Further to your comment about connecting the base view, here is what I mean:
After creating your custom class and nib file, open the nib and highlight "Files Owner" on the left, then on the top right hand side, select the icon 3rd from the left, looks like an ID card or something. In the "Class" box, add the name of your custom class.
In your customClass, add an IBOutlet UIView property called baseView, and add a UIView that covers the view in IB at the root level, connect these two. Then add everything else on top of that
you code would now look something like this:
CustomImageView.h
#import <UIKit/UIKit.h>
#interface CustomImageView : UIView
{
IBOutlet UIView *baseView
IBOutlet UIImageView *imageView;
IBOutlet UILabel *caption;
IBOutlet UIActivityIndicatorView *activityIndicator;
}
#property (nonatomic, retain) IBOutlet UIView *baseView;
#property (nonatomic, retain) IBOutlet UIImageView *imageView;
#property (nonatomic, retain) IBOutlet UILabel *caption;
#property (nonatomic, retain) IBOutlet UIActivityIndicatorView *activityIndicator;
#end
CustomImageView.m
#import "CustomImageView.h"
#interface CustomImageView ()
#end
#implementation CustomImageView
#synthesize baseView, caption, imageView, activityIndicator;
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// Initialization code.
//
[[NSBundle mainBundle] loadNibNamed:#"<NIB NAME HERE>" owner:self options:nil];
[self addSubview:self.baseView];
}
return self;
}
#end
Provided you connect it all up in IB it should work fine, just remember to add the baseView
As mentioned earlier initWithNibName belongs to controllers.
As I think, you're going the wrong way.
you have a ViewController and want to add a customView, to load dynamically a image from URLData.
You have 2 Options:
Option 1: Do everything in IB:
In Interfacebuilder edit/(or add a new one) the ViewController's XIB File and add the views that you like. The file's owner is a UIViewController Class/Subclass. Do everything like you did before, except doing it in the view controller. In your App delegate initWithNibName your ViewController like so
self.viewController = [[testViewController alloc] initWithNibName:#"testViewController" bundle:nil];
If you want to, initialize your own view controller, which you like to push and push it in the stack.
What you're doing wrong: You are initializing a customImageView with a Frame, but the nib doesn't get loaded automatically. The Properties are there, but the nib isn't.
If you really want a stable thing choose
Option 2: Do everything programatically (It is easier, more understanding and lightweight):
From your implementation we do the following:
NewsViewController.m
Do like you did before!!!
CustomImageView.h:
#import <UIKit/UIKit.h>
#interface CustomImageView : UIView
{
UIImageView *imageView;
UILabel *caption;
UIActivityIndicatorView *activityIndicator;
}
#property (nonatomic, retain) UIImageView *imageView;
#property (nonatomic, retain) UILabel *caption;
#property (nonatomic, retain) UIActivityIndicatorView *activityIndicator;
#end
CustomImageView.m:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
caption = [[UILabel alloc] initWithFrame:CGRectMake(0, 250, 320, 50)];
[caption setBackgroundColor:[UIColor greenColor]];
imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 250)];
[imageView setBackgroundColor:[UIColor blueColor]];
activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
self.activityIndicator.frame = CGRectMake(320/2-25, 460/2-25, 50, 50);
[self.activityIndicator startAnimating];
[self addSubview:self.caption];
[self addSubview:self.imageView];
[self addSubview:self.activityIndicator];
}
return self;
}
Then do everything you did before.
That would do a better job
I am not getting my image working. Can anyone tell me what I am doing wrong here?
musclePicture is a string in format of picture.png
1st view:
NSString *muscleURL = [[self.muscleArray objectAtIndex:indexPath.row]objectForKey:#"musclePicture"];
specificExerciseTableViewController.muscleImage = [UIImage imageNamed:muscleURL];
2nd view:
detailViewController.muscleImage = self.muscleImage;
3rd view:
self.image = [[UIImageView alloc]initWithImage:muscleImage];
[image release];
Edit:
MusclesTableViewController.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *muscleURL = [[self.muscleArray objectAtIndex:indexPath.row]objectForKey:#"musclePicture"];
specificExerciseTableViewController.muscleImage = [UIImage imageNamed:muscleURL];
}
SpecificExerciseTableViewController.h
#property (nonatomic, retain) UIImage *muscleImage;
SpecificExerciseTableViewController.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
detailViewController.muscleImage = self.muscleImage;
}
DetailViewController.h
#property (nonatomic, retain) UIImage *muscleImage;
#property (nonatomic, retain) IBOutlet UIImageView *image;
DetailViewController.m
- (void)viewDidLoad
{
self.image.image = muscleImage;
}
Try by giving a frame to your UIImageView after:
self.image = [[UIImageView alloc]initWithImage:muscleImage];
[image setFrame:CGRectMake(0,0,50,50)];
[image release];
Try this code snippet:
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[animal imageURL]]];
UIImage *animalImage = [[UIImage alloc] initWithData:imageData];
Assign it your UIImageView or UIImage.
I think you forgot to add image as subView to your view.
like this
[self.view addSubView:image];
or you are having a class variable that is connected to .xib file as an IBOutlet and you are reinitializing it using alloc and init, if that is the case then you have to do
self.image.image = [UIImage imageNamed: muscleImage];