UIWebViewDelegate functions have not been called - objective-c

.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.

Related

UIViewController Retaining in ARC

I have a subclass of UIViewController -> MyPopUpViewController
#protocol MyPopUpViewController Delegate;
#interface MyPopUpViewController : UIViewController
{
}
#property (nonatomic, strong) id <MyPopUpViewControllerDelegate> delegate;
-(IBAction) buttonPressed:(id)sender;
#end
#protocol MyPopUpViewControllerDelegate
-(void) popupButtonPressed: (MyPopUpViewController*)controller;
#end
I cannot have this MyPopUpViewController as an instance variable because this comes externally, and there could be many and multiple of these popups can be up. So far I tried this, and it crashes on the delegate call due to not being retained:
MyMainViewController:
-(void)externalNotificationReceived: (NSString*) sentMessage
{
MyPopUpViewController *popupView = [[MyPopUpViewController alloc] init];
popupView.delegate = self;
[self.view addSubview:popupView.view];
[popupView setInfo :sentMessage :#"View" :#"Okay"];
popupView.view.frame = CGRectMake(0, -568, 320, 568);
popupView.view.center = self.view.center;
}
-(void)popupButtonPressed:(MyPopUpViewController *)controller :(int)sentButtonNumber
{
NSLog(#"Popup Delegate Called");
[controller.view removeFromSuperview];
controller.delegate = nil;
controller = nil;
}
Once the popup comes up, and when the ok button is tapped, it crashes and never gets to that NSLog. How can I change
MyPopUpViewController *popupView = [[MyPopUpViewController alloc] init];
..so it would retain without making it an instance variable?
Thanks in advance.
You should be doing proper view controller containment by calling addChildViewController:.
- (void)externalNotificationReceived: (NSString*) sentMessage {
MyPopUpViewController *popupView = [[MyPopUpViewController alloc] init];
popupView.delegate = self;
[popupView setInfo :sentMessage :#"View" :#"Okay"];
popupView.view.frame = CGRectMake(0, -568, 320, 568);
popupView.view.center = self.view.center;
[self addChildViewController:popupView];
[self.view addSubview:popupView.view];
[popupView didMoveToParentViewController:self];
}
This will keep a proper reference to the view controller as well as properly pass various view controller events. Read about this in the docs for UIViewController and the "View Controller Programming Guide for iOS".
BTW - you should name your methods better. Example:
popupButtonPressed::
should be named:
popupButtonPressed:buttonNumber:
Usually delegates are weak-referenced instead of strong. I, myself, would name it something else as to not confuse other people.
Also, the following bit of code will have no effect:
-(void)popupButtonPressed:(MyPopUpViewController *)controller :(int)sentButtonNumber
{
...
controller = nil;
}
the controller would be released (set to nil) automatically at the end of the scope.

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

UIGestureRecognizer - Get the reference to the touched UIViewController Instead of its View?

How do I get a reference to the UIViewController of a touched view?
I am using a UIPanGestureRecognizer on the view of a UIViewController. Here's how I initialize it:
TaskUIViewController *thisTaskController = [[TaskUIViewController alloc]init];
[[self view]addSubview:[thisTaskController view]];
UIPanGestureRecognizer *panRec = [[UIPanGestureRecognizer alloc]initWithTarget:self action:#selector(handlePan:)];
[[thisTaskController view] addGestureRecognizer:panRec];
In the tiggered action triggered using the gesture recognizer I am able to get the view from the parameter using recognizer.view
- (IBAction)handlePan:(UIPanGestureRecognizer *)recognizer {
UIView *touchedView = [[UIView alloc]init];
touchedView = (UIView*)[recognizer view];
...
}
However what I really need is the underlying UIViewController of the view touched. How can I get a reference to the UIViewController that contains this view instead of only the UIView?
I would say that it is more a design issue than just getting a reference. So I would follow several simple advises:
Owner should catch events from its view. I.e. TaskUIViewController sould be a target to UIPanGestureRecognizer which you added to its view.
If a controller has a sub-controller and waits from its sub-controller some responses - implement this as delegate.
You have memory leak in your "handlePan:" method.
Here is a skeleton to solve your issue:
#protocol CallbackFromMySubcontroller <NSObject>
- (void)calbackFromTaskUIViewControllerOnPanGesture:(UIViewController*)fromController;
#end
#interface OwnerController : UIViewController <CallbackFromMySubcontroller>
#end
#implementation OwnerController
- (id)init
{
...
TaskUIViewController *thisTaskController = [[TaskUIViewController alloc] init];
...
}
- (void)viewDidLoad
{
...
[self.view addSubview:thisTaskController.view];
...
}
- (void)calbackFromTaskUIViewControllerOnPanGesture:(UIViewController*)fromController
{
NSLog(#"Yahoo. I got an event from my subController's view");
}
#end
#interface TaskUIViewController : UIViewController {
id <CallbackFromMySubcontroller> delegate;
}
#end
#implementation TaskUIViewController
- (id)initWithOwner:(id<CallbackFromMySubcontroller>)owner
{
...
delegate = owner;
...
}
- (void)viewDidLoad
{
UIPanGestureRecognizer *panRec = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePan:)];
[self.view addGestureRecognizer:panRec];
[panRec release];
}
- (void)handlePan:(UIPanGestureRecognizer *)recognizer {
...
[delegate calbackFromTaskUIViewControllerOnPanGesture:self];
...
}
#end
[touchedView nextResponder] will return the UIViewController object that manages touchedView (if it has one) or touchedView's superview (if it doesn’t have a UIViewController object that manages it).
For more information, see the UIResponder Class Reference. (UIViewController and UIView are subclasses of UIResponder.)
In your case, since you happen to know that touchedView is your viewController's view (and not, for instance, a subview of your viewController's view), you can just use:
TaskUIViewController *touchedController = (TaskUIViewController *)[touchedView nextResponder];
In the more general case, you could work up the responder chain until you find an object of kind UIViewController:
id aNextResponder = [touchedView nextResponder];
while (aNextResponder != nil)
{
if ([aNextResponder isKindOfClass:[UIViewController class]])
{
// we have found the viewController that manages touchedView,
// so we break out of the while loop:
break;
}
else
{
// we have yet to find the managing viewController,
// so we examine the next responder in the responder chain
aNextResponder = [aNextResponder nextResponder];
}
}
// outside the while loop. at this point aNextResponder points to
// touchedView's managing viewController (or nil if it doesn't have one).
UIViewController *eureka = (UIViewController *)aNextResponder;

Immediately starting new UIViewController from a viewcontroller

When the UIViewController starts, I want to start another UIViewController immediately.
This doesn't work:
-(void) awakeFromNib {
UIViewController *newcontroller = [[[UIViewController alloc] init] autorelease];
...
[self presentModalViewController:newcontroller animated:YES];
}
In order for this to work, I have to do afterDelay for a method, like so:
-(void) awakeFromNib {
[self performSelector:#selector(startNewController) withObject:nil afterDelay:0.5];
[super init];
}
-(void) startNewController {
UIViewController *newcontroller = [[[UIViewController alloc] init] autorelease];
...
}
Is it possible to get it to work without delay?
Call startNewController in your viewDidAppear method instead, that happens because your viewController is not totally loaded when you try to present the modal viewController, so that's why it works when you wait.
Practically, you should not plan your application architecture which forces you to do such implementations. Though, I can understand there are times where you have no way out..
I'd say:
best solution for your case is to call your controller from
viewDidAppear
or
viewWillAppear

Calling SEL from parentViewController in iOS

I have a ViewController in which I create a Modal ViewController. I have a SEL value in my modal that I set when it is being instantiated from the parent.
setDateViewController.selectorName = #selector(myMethod:);
In my modal I am trying to call this SEL like:
[[self parentViewController] performSelector:self.selectorName withObject:selectedDate afterDelay:.5];
{selectedDate} is obviously a value from my modal.
I don't get any errors or stack, however, this SEL (method) on my parent is never being called. For some reason I think this should work, but something tells me I'm way off track.
Thanks.
I guess [self parentviewcontroller] is not returning anything.
Try UiviewController* v = [self parentviewcontroller]; and check if is nil. Most probably it should be nil. Else if its was pointing to another object of different class then it would have crashed. Please do one thing. YOu should set bot the object and the methd you need to call. IT will solve any issues if it has any.
setDateViewController.selectorDelegate = self;
setDateViewController.selectorName = #selector(myMethod:);
call like this from parent class. So you can dynamically specify the method and the object you want to call gives more flexibility.
and use,
[selectorDelegate performSelector:self.selectorName withObject:selectedDate afterDelay:.5];
this should solve any issues.
Perhaps you would consider added a delegate protocol to your modal that will allow it to call the method on the parent.
Quick (untested) example:
// MyController.h
#protocol MyControllerDelegate;
#interface MyController : UIViewController
{
id<MyControllerDelegate> delegate;
}
#end
#protocol MyControllerDelegate <NSObject>
- (void)methodToCall:(id)sender;
#end
// MyControler.m
#implementation MyController
- (void) loadView
{
[super loadView];
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.frame = CGRectMake(20.0f, 20.0f, 50.0f, 30.0f);
[btn setTitle:#"blah" forState:UIControlStateNormal];
[btn addTarget:self.delegate
action:#selector(methodToCall:)
forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn];
}
#end
// ParentController.h
#interface ParentController : UIViewController<MyControllerDelegate>
{
}
#end
// ParentController.m
#implementation ParentController
- (void)methodToCall:(id)sender
{
NSLog(#"HERE");
}
#end
Just make sure when you are creating your modal controller you set it's delegate to self on the parent:
MyController *controller = [[MyController alloc] init];
controller.delegate = self;
[self presentModalViewController:controller animated:YES];