(iOS) How can I Reuse an UIImageView in another View? - objective-c

I have a view controller with a UIScrollView with a heap of UIImageViews as subviews. There is a segue to another view controller but i want to reuse the UIImages that are already in memory rather than load them again for efficiency's sake. But if I point my new UIImageView to an existing one, nothing shows up.
I had to use an intermediate pointer variable (imageViewPointer) as if I assign it directly in the prepareForSegue method, the NSLog's from each view controller would show different addresses. This workaround NSLogs show the same address but still nothing shows up.
If I use reassign the .image property instead, the image shows up but the images from the first view controller are load asynchronously so the .image property might change.
In the first view controller
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NextViewController *nextViewController = [segue destinationViewController];
nextViewController.imageViewPointer = [[myScrollView subviews] objectAtIndex:myIndex];
NSLog(#"%#", [[myScrollView subviews] objectAtIndex:myIndex]);
}
In the second view controller
#interface nextViewController : UIViewController
#property (retain, nonatomic) IBOutlet UIImageView *imageView;
#property (retain, nonatomic) UIImageView *imageViewPointer;
#implementation nextViewController
#synthesize imageView, imageViewPointer;
{
self.imageView = self.imageViewPointer;
// [self.imageView setNeedsDisplay]; Doesn't help
NSLog(#"IMAGE VIEW POINTER = %#", self.imageViewPointer);
NSLog(#"IMAGE VIEW = %#", self.imageView);
[super viewDidLoad];
}

If you simply assign a view like that, it won't appear in the view hierarchy of your current view controller's view. You'll need to do something like:
[self.view addSubview: imageView];
However, I wouldn't recommend that. It is better to just assign the image of the view to the image of the other view.
self.imageView.image = self.imageViewPointer.image;

Either you reuse the UIImage or the method you are doing is a bit wrong as you are assigning the imageViewPointer to imageView which is(imageViewPointer) not a subview of your view controller's view. So add subview imageViewPointer or imageView after assigning imageViewPointer.

Related

UILabel not updating even though it is connected to IBOutlet and IBOutlet has correct value

I have a TableViewCOntroller that shows a list of images and associated descriptions. I pass data to the detailed view in the prepare for segue method. THe MSMutableDrictionary Object I pass has the correct values and I can see this in the NSLog of the object in the detail views viewDidLoadMethod. THe code for this is as follows:
.h of detail view controller
#interface sitespecLargeImageDetail : UIViewController
#property (strong, nonatomic) NSMutableDictionary *details;
#property (strong, nonatomic) IBOutlet UIImage *largeImage;
#property (strong, nonatomic) IBOutlet UILabel *largeImageLabel;
#end
.m of detail view controller
#implementation sitespecLargeImageDetail
- (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.
_largeImage = [_details valueForKey:#"pbvurl"];
_largeImageLabel = [_details valueForKey:#"pbvdesc"];
NSLog(#"%#", _largeImageLabel);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Here is the prepare for segue event in the tableviewcontoller:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
sitespecLargeImageDetail *detailViewController = (sitespecLargeImageDetail *)segue.destinationViewController;
detailViewController.details = _dictObj;
}
Couple of strange things:
WHen I look at the detail view controller in my storyboard in the connections inspector, I can see both the label and image Outlets. I can see I ahve connected the label outlet. great, but it does not update when the view loads! I know the dict obj in the detail view gets data because I can NSLog it and see it. I use that to set the IBOutlet for the label but nothing.
In the connection inspector, I can see the UIImage outlet BUT I am unable to connect it to the UIImage VIew I placed in the detail view controller, it simply wont allow me to connect it, no error, just when I control drag from the detailview controller I dont even see it! I see the label outlet, but not the image view.......
Firstly, what you want to do is _largeImageLabel.text = [_details valueForKey:#"pbvdesc"];.
Without the .text what you are doing is using the UILabel pointer to point to a NSString, which clearly does not result in your expected behaviour!
As for the UIImage outlet, what you need is a UIImageView outlet! UIImage is not a view, hence it doesn't have any relation with the interface builder (you can't drag a UIImage in your storyboard, only views can compose interfaces).

Calling a method in custom view

I am creating a simple drawing app with a custom view that draws lines on the screen. I am calling a method in my custom view .m file from my viewcontroller file. I've got it set up so it autocompletes my method, which means that it knows it exists, but isn't firing.
In my custom View BezierSigCapView.m
- (void)erase {
path = [UIBezierPath bezierPath];
[pointsArray removeAllObjects];
[self setNeedsDisplay];
NSLog(#"ERASE!");
}
In my View Controller.h file
#property (weak, nonatomic) BezierSigCapView *myView;
In my View Controller.m file
/// in viewDidLoad
BezierSigCapView *theView = [[BezierSigCapView alloc] init];
self.myView = theView;
/// my button code
- (IBAction)ClearButton:(UIBarButtonItem *)sender {
[self.myView erase];
NSLog(#"Should Erase");
}
Kindly check if you have connected the - (IBAction)ClearButton:(UIBarButtonItem *)sender;
to the button.
#hermann pointed me in the right direction. I was creating the view programmatically and in interface builder. I deleted the view that I created programmatically and hooked up an Outlet to the view on interface builder as a property. I also got rid of "theView" which was redundant.
//In view controller.h file
#property (strong, nonatomic) IBOutlet BezierSigCapView *myView;
//In view controller.m file
//in the implementation
#synthesize myView;
//I also removed the code below from the view controller.m file that was causing another issue
self.myView = [[BezierSigCapView alloc] init];

How to pass an uiimage to another view controller?

How to pass the uiimage selected in uiimagepickercontroller in MainViewController to SecondViewController? It did push to the SecondViewController, however the uiimage is empty.
I've searched through the web, tried with the solutions but still cannot get it work.
photoImage is the uiimageview I've declared in SecondViewController.
- (void)imagePickerController:(UIImagePickerController *) picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
[picker dismissModalViewControllerAnimated:YES];
SecondViewController *secondVC = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
[secondVC.photoImage setImage:[info objectForKey:#"UIImagePickerControllerEditedImage"]];
[self.navigationController pushViewController:secondVC animated:YES];
[secondVC release];
}
A UIImageView in your second view controller doesn't exist until the viewDidLoad method of that controller is called. Put a property into SecondViewController that holds a UIImage, store the reference to the image you want to use in it when you push the view controller (instead of trying to set the image view), and then move your setImage: call into the second view controller's `viewDidLoad``.
Create a shared class that will store the image, and access it wherever you want.
In MainViewController assign that image in that shared class' ivar, and in SecondViewController access it.
Edit :
Below code shows how to implement shared class, this may not be syntactically correct, because currently I am not using mac, so I cant complile.
#interface SomeManager : NSObject
+(id)myImage;
#end
#implementation SomeManager
+(id)myImage{
static id myImage= nil;
#synchronized([self class]){
if (myImage== nil) {
myImage= //put your image here;
}
}
return myImage;
}
#end

Is there anyway to know where a popover was presented from?

I'm writing an iPad app and one of my screens has lots of small buttons that when pressed will display one sentence of text in a popover originating from that button. Currently all popovers are created using the storyboard and I store the popover controller in my UIViewController as such:
#property (nonatomic, strong) UIPopoverController *myPopoverController;
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue isKindOfClass:[UIStoryboardPopoverSegue class]])
{
UIStoryboardPopoverSegue *popoverSegue = (UIStoryboardPopoverSegue *)segue;
self.myPopoverController = popoverSegue.popoverController;
}
}
However, I can't figure out a good way to deal with rotation. Right my didRotate method looks like so:
- (void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
if (self.myPopoverController)
{
[self.myPopoverController dismissPopoverAnimated: NO];
[self.myPopoverController presentPopoverFromRect:?????? inView:self.view permittedArrowDirections:UIPopoverArrowDirectionDown animated:NO];
}
}
However, I don't know where to present the popovers from given that they could have originated from any of the small buttons on my screen. Any suggestions? Remember that these are VERY simple popovers, thus a whole bunch of new code is not ideal.
Your best bet may be to make another property in your main view controller that keeps a reference to the button pressed. Something like:
#property (nonatomic, strong) UIPopoverController *myPopoverController;
#property (nonatomic, weak) UIView *popoverButton;
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue isKindOfClass:[UIStoryboardPopoverSegue class]])
{
UIStoryboardPopoverSegue *popoverSegue = (UIStoryboardPopoverSegue *)segue;
self.myPopoverController = popoverSegue.popoverController;
//The sender in prepareForSegue should be the view used to initiate the segue.
popoverButton = (UIView *)sender;
}
}
That done, you can modify your rotation code thusly:
- (void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
if (self.myPopoverController)
{
[self.myPopoverController dismissPopoverAnimated: NO];
[self.myPopoverController presentPopoverFromRect:popoverButton.frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionDown animated:NO];
}
}
Keeping a reference to the pressed button takes up no more resources that storing a pointer, and keeping the reference weak should avoid retain cycles (after all, your view controller does not own the button, the button's superview owns it).

set UIImageView.image in prepareForSegue

I want to segue to a photoViewController that has an UIImageView.
In flickrTVC, I say:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"showPhoto"])
{
photoViewController *vc = [segue destinationViewController];
UIImage *photo = [UIImage imageWithContentsOfFile:#"images/en.jpeg"];
[vc setDisplayedPhoto:photo];
}
}
and the setDisplayedPhoto method's implementation is:
-(void)setDisplayedPhoto:(UIImage *)image
{
[_imageView setImage:image]; //#property (nonatomic, strong) IBOutlet UIImageView *imageView;
}
But when I do segue, the UIImageView is white... Why could this be?
Your destination view controller hasn't loaded its view hierarchy by the time your source view controller receives the prepareForSegue:sender: message. So your destination VC's _imageView variable is nil.
The recommended approach is to store the image (or, probably even better, the image file name) as a property of the destination VC, and then set the image view's image in the destination VC's viewDidLoad or viewWillAppear: method.
Call [vc view] before setting the o of the view