How to pass an uiimage to another view controller? - objective-c

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

Related

Unable to set content in NSPopover

I'm showing an NSPopover in an NSView, originating from a point on an NSBezierPath. I'm able to show the popover without a problem, but I can't seem to set the string value of the two text fields in it. The popover and the content view are both a custom subclass of NSPopover and NSViewController, respectively. The NSPopover subclass is also the NSPopover's delegate, although I don't implement any delegate methods, so I'm not sure I even need to do that.
Here is my subclass of NSViewController:
#import <Cocoa/Cocoa.h>
#interface WeightPopoverViewController : NSViewController
#end
#import "WeightPopoverViewController.h"
#interface WeightPopoverViewController ()
#end
#implementation WeightPopoverViewController
- (id)init {
self = [super initWithNibName:#"WeightPopoverViewController" bundle:nil];
if (self) {
}
return self;
}
#end
And my subclass of NSPopover:
#import <Cocoa/Cocoa.h>
#interface WeightPopoverController : NSPopover <NSPopoverDelegate> {
NSTextField *dateLabel;
NSTextField *weightLabel;
}
#property (strong) IBOutlet NSTextField *dateLabel;
#property (strong) IBOutlet NSTextField *weightLabel;
#end
#import "WeightPopoverController.h"
#implementation WeightPopoverController
#synthesize weightLabel;
#synthesize dateLabel;
#end
This is the code in my NSView subclass that opens up the popover:
#interface WeightGraphViewController () {
WeightPopoverController *popover;
WeightPopoverViewController *vc;
}
...
-(void)mouseEntered:(NSEvent *)theEvent {
// initialize the popover and its view controller
vc = [[WeightPopoverViewController alloc] init];
popover = [[WeightPopoverController alloc] init];
// configure popover
[popover setContentViewController:vc];
[popover setDelegate:popover];
[popover setAnimates:NO];
// set labels
for (id key in (id)[theEvent userData]) {
[popover.weightLabel setStringValue:[(NSDictionary*)[theEvent userData] objectForKey:key]];
[popover.dateLabel setStringValue:key];
}
// set the location
(redacted, irrelevant)
// show popover
[popover showRelativeToRect:rect ofView:[self window].contentView preferredEdge:NSMaxYEdge];
}
-(void)mouseExited:(NSEvent *)theEvent {
[popover close];
popover = nil;
}
In WeightPopoverViewController.xib, I've set the File's Owner to WeightPopoverViewController and connected the view to the custom NSView. In this xib I also have an Object set to WeightPopoverController with the dateLabel and weightLabel connected to their text fields and the contentViewController set to File's Owner.
I think where I am going wrong is likely related to how I have configured my class / instance variables for the NSPopover, but from the research I've done and documentation I've read I can't seem to crack where I've gone wrong. Any help would be appreciated.
UPDATE:
I removed the NSPopover subclass from code and from IB. I put my outlets in my NSViewController and connected them in IB. However, I'm still not able to set the string values. The following won't compile with the error "Property 'weightLabel' not found on object of type NSPopover*'".
#interface WeightGraphViewController () {
NSPopover *popover;
...
}
-(void)mouseEntered:(NSEvent *)theEvent {
vc = [[WeightPopoverViewController alloc] init];
popover = [[NSPopover alloc] init];
[popover setContentViewController:vc];
[popover.dateLabel setStringValue:#"test"];
}
I have the property definition exactly as I had it in my NSPopover subclass, but now in my NSViewController. This is actually what I had before, and since I wasn't able to set the properties from the NSViewController, I figured I needed to do it through a subclass of NSPopover. This is why I thought I am having an issue with how I have configured my class / instance variables.
You seem to be creating two popovers, one in code (popover = [[WeightPopoverController alloc] init]) and one in Interface Builder (In this xib I also have an Object set to WeightPopoverController). Have a think about what you’re trying to achieve.
I would also advise against subclassing NSPopover. I believe this is causing confusion and is unnecessary. Instead, put the outlets to your dateLabel and weightLabel in the popover’s content view controller.
I've experienced something that I think is similar. The root problem is that the "outlets" connecting your view (XIB) to your controller are not initialized until after the view has been displayed. If the controller tries to set properties on any UI controls in the view before the popover has been opened, those changes are ignored (since all the controls will be nil).
Luckily, there's an easy solution (as mentioned in this answer): just invoke the view getter on your controller, and it will force the view to initialize sooner.
In other words:
popover = [NSPopover new];
myController = [[MyViewController alloc] initWithNibName:#"MyView" bundle:nil];
popover.contentViewController = myController;
[myController view]; // force view to initialize
...set some values on myController... // works because view is now loaded
[popover showRelativeToRect: ...];

iPhone back button refuses to work after selecting an image with the UIImageViewController? [duplicate]

This question already has answers here:
iPhone - UIImagePickerControllerDelegate inheritance
(2 answers)
Closed 9 years ago.
So I am writing this iPad app that starts on a main screen and then from there you can go to a settings page. In the settings page you have the ability to select a picture from the photo album using a UIImagePickerController in a popover view.
If I go to the settings page and then press the back button to return to the main page everything works as expected. But if I go to settings and pick an image the back button on the page will not let me go back to the main page.
The popover and UIImagePickerController seem to be working fine so I do not know what is causing this. Here is my code for the UIImagePickerController.
- (IBAction)imagePick1:(id)sender {
pickerController = [[UIImagePickerController alloc] init];
[pickerController setDelegate:self];
[pickerController setSourceType:UIImagePickerControllerSourceTypeSavedPhotosAlbum];
[pickerController setAllowsEditing:NO];
popoverController = [[UIPopoverController alloc] initWithContentViewController:pickerController];
[popoverController setDelegate:self];
[popoverController presentPopoverFromRect:[[self imageButton1] frame] inView:[self view] permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
...
- (void)imagePickerController:(UIImagePickerController *)pickerController1 didFinishPickingMediaWithInfo:(NSDictionary *)info
{
image1 = [info objectForKey:UIImagePickerControllerOriginalImage];
_image1.image = image1;
[popoverController dismissPopoverAnimated:YES];
}
When I try to press the back button the app freezes and it won't respond to any more commands. What am I doing wrong?
Edit: I ran it again and this is the error I got in the log when pressing the back button.
-[__NSCFType dismissPopoverAnimated:]: unrecognized selector sent to instance 0x7128cd0
Also here is the beginning of my header file.
#interface ViewController : UIViewController
<UIPickerViewDataSource, UIPickerViewDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate, UIPopoverControllerDelegate>{
UIPopoverController *popoverController;
}
#property (nonatomic, retain) UIPopoverController *popoverController;
Possible duplicate. See here
Have you declared the delegate in the header file as well like below? Please also make sure your delegates conforms to the UINavigationControllerDelegate as well, as the UIImagePickerControllerDelegate directly inherits from UINavigationControllerDelegate, however all the UINavigationControllerDelegate methods are optional.
#interface MyViewController : UIViewController <UIImagePickerControllerDelegate, UINavigationControllerDelegate>
edit: Based on your edit, it appears that you need to also add the "UIPopoverControllerDelegate" to your header file. You also need to add [popoverController setDelegate:self] after your allocation.
edit 2: Ok now you need to declare this method as well in your implementation (.m) file.
and return yes.
- (BOOL)popoverControllerShouldDismissPopover:(UIPopoverController *)popoverController {
return YES;
}
edit 3: Why are you are setting dismissPopoverAnimated to NO and releasing popoverController while it is still showing?
[popoverController dismissPopoverAnimated:NO];
[popoverController release];
try setting the dismissPopoverAnimated to YES and remove the release for now. By the way, is popoverController retained as a property in your header file? Are you using ARC? if you are using ARC you should not be calling release on the popoverController.
edit 4:
try modifying the header to this:
UIPopoverController *_popoverController;
#property (nonatomic, retain) UIPopoverController *popoverController
and add #synthesize popoverController = _popoverController; to your implementation file.
now start replacing all the instances of "popoverController" with "_popoverController" in your implementation file.
Also replace [popoverController dismissPopoverAnimated:YES]; with
if(_popoverController != nil)
[_popoverController dismissPopoverAnimated:YES];
let me know the results below.

UIWebViewDelegate functions have not been called

.h file:
#interface MyView: UIViewController <UIWebViewDelegate> {
UIWebView *webView;
}
.m file:
-(void)viewDidLoad {
CGRect webFrame = [[UIScreen mainScreen] applicationFrame];
webView= [[UIWebView alloc] initWithFrame:webFrame];
webView.delegate = self;
[self.view addSubview:webView];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://google.com"]]];
}
-(void)webViewDidStartLoad:(UIWebView *)webView {
NSLog(#"start");
}
-(void)webViewDidFinishLoad:(UIWebView *)webView {
NSLog(#"finish");
}
-(void)dealloc {
webView.delegate = nil;
webView = nil;
}
create MyView in another ViewController:
MyView * myView = [[MyView alloc] init];
[self.view addSubView:myView.view];
myView = nil;
myView is set to be nil so its delegate is also destroyed.
To solve this, remove the sentence of myView = nil.
Thank you guys who answered me. I did learnt from your answers.
As srikanth said myview is a controller and it needs to be told its on screen and retained so it doesnt go away AND that is your immediate the real issue in your case (I think). Nobody retains myView.
make it a member variable so it isnt released directly after it gave you its view :).
#interface MyCallerWithDoesTheASI : NSObject {
MyView *myView;
}
#end
or do it right and add it like srikanth said ::
[self addChildViewController:myView];
[self.view addSubview:myView.view];
[myView didMoveToParentViewController:self];
or for example and present myView modal
[self presentViewController:myView animated:NO completion:^{ [[myView dismiss...]; }
MyView is a view controller. And you are treating it like a view, in the second case. If you want to add a view of a view controller directly, it will not get all of the view controller methods called. To be able to get the correct functionality, you will have to do some thing different.
Assuming you are in another view controller then in the other view controller, when ever you want to add the view of MyView view controller, do the following
[self addChildViewController:myView];
[self.view addSubview:myView.view];
[myView didMoveToParentViewController:self];
But even before doing that, please use correct naming convention. If you are naming a subclass of UIViewController as MyView, you will confuse yourself. Name it as MyViewController. That way, you will be able to keep track of stuff better.
Read more about view controller containment for your problem.

Pushing a controller from a subview

In essence what is the correct way of pushing a new view controller from a sub view of a navigation controller.
The issue being subviews of the navigation view don't inherit the self.navigationController (its nil)
The reason is I need separate controllers for the navigation bar view & the main view but both need to push new controllers.
I am willing to change this model if someone can tell me the correct way of doing this.
Also:
AppDelegate *del = (AppDelegate *)[UIApplication sharedApplication].delegate
[del.navigationController pushViewController:vc animated:YES];
Does not work as the delegates controller is nil.
Create a following category on UIView.
#interface UIView (GetUIViewController)
- (UIViewController *)viewController;
#end
#implementation UIView (GetUIViewController)
- (UIViewController *)viewController;
{
id nextResponder = [self nextResponder];
if ([nextResponder isKindOfClass:[UIViewController class]]) {
return nextResponder;
} else {
return nil;
}
}
#end
Now get the SuperView from the subView.
mySuperView = [mySubView superview];
Then call the method from category created.
mySuperViewController = [mySuperView viewController];
Now, using this viewController, you can access the navigationController.
I have not tried the above code and approach, but I hope it should work.
You may try two ways
1.Use the superViewController's navigationController to push your viewController
2.Embed your current viewController in a NavigationController so that the navigationController won't be nil

Protocol is not calling methods

I have a modal view which gets the user to select some data to add to a table. When the user presses a save button, the modal view should disappear and send the required data back to the view controller that presented the modal view for further processing. To achieve this, I have set up a protocol. The protocol method in the original view controller does not get called. My code is below, what am I doing wrong?
The header file (modal view controller):
#protocol AddTAFDataSource;
#interface AddTAFViewController : UIViewController <UIPickerViewDelegate, UIPickerViewDataSource> {
id<AddTAFDataSource> dataSource;
NSString *newICAOCode;
}
#property (nonatomic, assign) id<AddTAFDataSource> dataSource;
- (IBAction)saveButtonPressed;
#end
#protocol AddTAFDataSource <NSObject>
- (void)addNewTAF:(AddTAFViewController *)addTAFViewController icao:(NSString *)icaoCode;
#end
The implementation file (modal view controller):
#import "AddTAFViewController.h"
#import "TAFandMETARViewController.h"
#implementation AddTAFViewController
#synthesize dataSource;
...
- (IBAction)saveButtonPressed {
[self.dataSource addNewTAF: self icao: newICAOCode];
}
#end
Presenting view controller header file:
#import "AddTAFViewController.h"
#interface TAFandMETARViewController : UITableViewController <AddTAFDataSource> {
}
#end
And finally, the presenting view controller:
#import "AddTAFViewController.h"
...
- (void)insertNewObject:(id)sender {
AddTAFViewController *addTAFViewController = [[AddTAFViewController alloc] initWithNibName: #"AddTAF" bundle: [NSBundle mainBundle]];
addTAFViewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[(AddTAFViewController *)self.view setDataSource: self];
[self presentModalViewController: addTAFViewController animated: YES];
addTAFViewController = nil;
[addTAFViewController release];
}
- (void)addNewTAF:(AddTAFViewController *)addTAFViewController icao:(NSString *)icaoCode {
newICAO = icaoCode;
[self dismissModalViewControllerAnimated: YES];
}
Just to remind, it is the above -(void)addNewTAF: method that does not get messaged. Any help/pointers in the right direction are much appreciated.
Replace:
[(AddTAFViewController *)self.view setDataSource: self];
With:
[addTAFViewController setDataSource:self]
After all, the dataSource is a property of the controller, not a controller's view.
Rather than trying to use a separate object (your dataSource) to pass data between the two view controllers, you could simply use add properties to contain the data directly in the view controller you're going to present modally (here, the AddTAFViewController).
Then in the method you use to dismiss the modal view controller, before dismissing it you can send [self modalViewController] to get the modal view controller, and at that point the parent view controller can send it any messages it wants. That would allow you to grab whatever data you need from the modal view controller, so you wouldn't need the data source and the protocol at all.
You are wrong at this point:
[(AddTAFViewController *)self.view setDataSource: self];
you should write this instead:
addTAFViewController.dataSource = self;