retain viewcontroller - message sent to deallocated instance - ios

I'm trying to use the UIWebViewDelegate, however, when I set delegate to it's self, I get a 'message sent to deallocated instance' error.
Actual error: "2014-04-07 22:12:05.402 AppName[746:60b] -[WebViewController respondsToSelector:]: message sent to deallocated instance 0xa47ae00"
I presume this is because the WebViewController instance has not been retained?
Could anyone point me in the right direction for this please?
My structure is:
RootViewController > WebViewController (delegate) > WebView
// root.h
#interface RootViewController : UIViewController
#property (strong, nonatomic) WebViewController * webViewController;
#end
// root.m
#import "RootViewController.h"
#import <UIKit/UIKit.h>
#import "WebViewController.h"
#interface RootViewController ()
#end
#implementation RootViewController
- (void)viewDidLoad
{
_webViewController = [[WebViewController alloc] init];
[self.view addSubview:_webViewController.view];
}
#end
// .h
#import <UIKit/UIKit.h>
#interface WebViewController : UIViewController <UIWebViewDelegate>
#property(strong) UIWebView *webView;
#end
// .m
#import "WebViewController.h"
#interface WebViewController ()
#end
#implementation WebViewController
- (void)viewDidLoad
{
_webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height)];
_webView.delegate = self;
NSString *url = #"http://google.com/";
NSURL *nsurl = [NSURL URLWithString:url];
NSURLRequest *nsrequest = [NSURLRequest requestWithURL:nsurl];
[_webView loadRequest:nsrequest];
[self.view addSubview:_webView];
}
-(void)webViewDidStartLoad:(UIWebView *)webView {
NSLog(#"ui web view started load");
}

Try moving your code out of loadView into viewDidLoad, and remove your calls to loadView. I believe loadView is called automatically when the view controller is instantiated and shown, so calling it again might cause you to instantiate your webview twice.
From the docs:
You should never call this method directly. The view controller calls
this method when its view property is requested but is currently nil.
This method loads or creates a view and assigns it to the view
property.

I had not set the root view controller like so:
self.window.rootViewController = rootController;

Related

Why does subclassing the main ViewController's view causes delegates to never fire?

I made a customView that implements its own delegate and set it up inside the main viewController. It works perfectly well, it's the standard practice, there's no need to show any code.
For the sake of better organizing the code I created a manager called customManager that contains the customView and the main viewController's view.
Instead of having all the code that it's needed inside the viewController (managing how the customView is setup and also listening to its delegate) I moved all that code to the customManager instead. That's why I made the customManager just to clear up the code that's inside the viewController.
All renders properly but the delegate never fires.
CustomManager.h
#import "CustomView.h"
#interface CustomManager : NSObject <CustomViewDelegate>
#property (weak) UIView *view; // viewController's view
#property (strong) CustomView *customView;
- (void)load;
#end
CustomManager.m
#import "CustomManager.h"
#implementation CustomManager
// Initialization Method
- (void)load {
_customView = [[CustomView alloc] init];
_customView.delegate = self; // !!!
_customView.frame = CGRectMake(0.0, 20.0, _view.frame.size.width, _view.frame.size.height - 20.0);
[_view addSubview:_customView];
}
#pragma mark - CustomViewDelegate
// Delegate Methods
#end
ViewController.h
#import "CustomManager.h"
#interface ViewController : UIViewController
#property (strong) CustomManager *customManager;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
_customManager = [[CustomManager alloc] init];
_customManager.view = self.view;
[_customManager load];
// 1. The load method above removes the code needed here for initializing the customView and setting it up correctly.
// 2. The delegate methods are now in the customManager and leave the space below clear.
}
#end

call functions on a uiwebview controller outside the Viewcontroller class in objective C

I have a uiwebview in my ios program and it is connected to a variable inside the ViewController interface
#interface ViewController() <UIWebViewDelegate>
#property(weak, nonatomic) IBOutlet UIWebView *uiwebview;
#end
I want to call functions on this uiwebview from outside the viewcontroller
For example, I can control the webview just fine if it is used between
#implementation ViewController
.
.
.
#end
But I want to use it somewhere outside. For example, I want to do something like this
[uiwebview loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"about:blank"]]];
from outside #implementation ViewController
What are the options to achieve this?
But I want to use it somewhere outside. For example, I want to do something like this
[uiwebview loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"about:blank"]]];
from outside #implementation ViewController
Stop wanting that. An IBOutlet should be private to its own view controller. If you want other view controllers to be able to do something to that web view, then arm your ViewController with public methods that they can call.
I think I understand what you are trying to do, I have an app that has various tabs some of which are web view. When my app starts I get it to pre-load the web views so that when the tabs are selected they are already loaded. Its important the the other tabs are all singleton classes so that there is only one instance of them.
In my main ViewController viewDidLoad I have this ..
//Pre load calculators and status page
EvolutionViewController *evoCalc = [EvolutionViewController sharedInstance];
[evoCalc.view layoutSubviews];
IVCalcViewController *ivCalc = [IVCalcViewController sharedInstance];
[ivCalc.view layoutSubviews];
StatusViewController *serverStatus = [StatusViewController sharedInstance];
[serverStatus.view layoutSubviews];
Those instantiate the classes for the other tabs which also loads up the web views associated with those classes. All the classes are similar this is the .h
#import <UIKit/UIKit.h>
#interface EvolutionViewController : UIViewController <UIWebViewDelegate>
+ (EvolutionViewController *) sharedInstance;
#property (nonatomic, retain) IBOutlet UIWebView *webView;
#end
And the .m
#import "EvolutionViewController.h"
#interface EvolutionViewController ()
#end
#implementation EvolutionViewController
#synthesize webView;
#pragma mark - Singleton Methods
static EvolutionViewController *_sharedInstance;
- (id) init
{
if (self = [super init])
{
// custom initialization
}
return self;
}
+ (EvolutionViewController *) sharedInstance
{
return _sharedInstance;
}
-(id)initWithCoder:(NSCoder *)decoder {
if (!_sharedInstance) {
if (self = [super initWithCoder:decoder]) {
_sharedInstance = self;
}
}
return _sharedInstance;
}
#pragma mark - View Controller Methods
-(void)viewWillLayoutSubviews {
self.webView = [[UIWebView alloc] init];
}
- (void)viewDidLoad {
[super viewDidLoad];
NSURL *url = [[NSBundle mainBundle] URLForResource: #"evo_calc" withExtension:#"html"];
NSURLRequest*request=[NSURLRequest requestWithURL:url];
[self.webView loadRequest:request];
}
#end
Mine uses local html resources but works the same with a proper URL as well.

UISplitViewController using delegate to pass a string

I'm using a Split View Controller for an iPad app. I'm trying to send a label change to the detailReceiving Controller from the rootSending Controll when a button is pushed. I've read through tutorials on protocols and came up with the code below. When I click the button on rootSending, nothing happens to the label on detailReceiving. Do I have to do something else with a splitViewContoller so that the label will update? Shouldn't detailReceiving change the label when it receives the message?
rootSending.h
#import <UIKit/UIKit.h>
#protocol TestDelegate <NSObject>
-(void)tester:(NSString*)testString;
#end
#interface rootSending : UIViewController
#property (nonatomic, assign) id <TestDelegate> delegate;
#end
rootSending.m
#import "rootSending.h"
#implementation rootSending
#synthesize delegate;
-(void)viewDidLoad{
}
-(IBAction)buttonPressed:(id)sender{
[delegate tester:#"button pressed"];
}
#end
detailReceiving.m
#import "detailReceiving.h"
#import "rootSending.h"
#interface detailReceiving ()<TestDelegate>{
IBOutlet UILabel *label2;
}
#end
#implementation detailReceiving
-(void)viewDidLoad{
rootSending *obj = [rootSending alloc];
obj.delegate = self ;
}
-(void)tester:(NSString *)testString{
label2.text = testString;
}
#end
First of all, never ever have an alloc without an init! But in this case, even if you did use alloc/init, it still wouldn't work because that just creates a new instance of rootSending, not the one that you have in your split view. You need to get a reference to the one you have, which you can get from the split view controller,
-(void)viewDidLoad{
rootSending *obj = (rootSending *)self.splitViewController.viewControllers.firstObject;
obj.delegate = self;
}
After Edit:
If your mate controller is embedded in a navigation controller, then you need to get the navigation controller's topViewController to get your reference.
-(void)viewDidLoad{
UINavigationController *nav = (UINavigationController *)self.splitViewController.viewControllers.firstObject;
xmlListOfItems *obj = (xmlListOfItems *)nav.topViewController;
obj.delegate = self;
}

Unable to load new URL to UIWebView from another controller

I am new to iOS and I'm trying to make an webview-based app with sidebar drawer and simple navigation (I'm using MFSideMenu library). I'm able to load URL with my webview:
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UIWebViewDelegate>{
UIWebView *webView;
}
#property (retain, nonatomic) IBOutlet UIWebView *webView;
- (IBAction)showLeftMenuPressed:(id)sender;
- (void) loadURL;
#property (nonatomic, strong) NSURL *url;
#end
ViewController.m
#import "ViewController.h"
#import "MFSideMenu.h"
#interface ViewController ()
- (void)webViewDidFinishLoad:(UIWebView *)webView;
#end
#implementation ViewController
#synthesize webView;
#synthesize url;
- (void)viewDidLoad
{
[super viewDidLoad];
webView.delegate=self;
if(self.url == Nil) {
NSString *myURL = #"http://google.com/";
self.url = [NSURL URLWithString:myURL];
}
[self loadURL];
}
-(void)loadURL{
NSLog(#"loadURL: %#", self.url);
[self.webView loadRequest:[NSURLRequest requestWithURL:self.url]];
}
When I'm trying to load new URL using following code, I'm receiving right url param value. Another controller is a sidebar (drawer) tableview where I'm selecting an item to change the URL showing in the main view (ViewController which contains webview).
Another controller:
ViewController *webViewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
NSString *urlString = #"http://kirk.kh.ua/";
NSString *encodedString=[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *url = [NSURL URLWithString:encodedString];
webViewController.url = url;
//[self.navigationController pushViewController:webViewController animated:YES];
[webViewController loadURL];
[webViewController release];
You may notice that there is a commented line - I have tried this solution, but result is the same: when I'm calling code in another controller nothing happens with the ViewController's webview which is strange because in log output I see that loadURL method was called and it gives me a right URL (kirk.kh.ua).
UPD: I have noticed that on the first load webview as an object, and then it appears to be null (see log):
UPD2: I have noticed that webivew object and other synthesized objects are null when I'm calling them from another class, but this objects exist and accessible when I'm logging them from self (ViewController) controller.
Can anyone suggest how can I access ViewController class objects from another class?
Instead of trying to open the URL from the Another Controller - make a NSString property in the ViewController, then when you tap a cell just pass the URL as a string:
ViewController *webViewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
webViewController.urlString = #"http://kirk.kh.ua/";
And then add in the ViewController add something like this in the viewWillAppear:
if (![self.urlString isEqualToString:#""]) {
NSString *encodedString=[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *url = [NSURL URLWithString:encodedString];
webViewController.url = url;
[webViewController loadURL];
}

Need assistance regarding passing data from child to parent in UINavigationcontroller

In UINavigationController this is child controller
.h
#protocol childProtocol <NSObject>
-(void)childMethod:(NSArray*)params;
#end
#property (strong, nonatomic) id<childProtocol>childDelegate;
#property (weak, nonatomic) parentVC *pVC;
.m
if([self.childDelegate respondsToSelector:#selector(childMethod:)]) {
[self.childDelegate performSelector:#selector(childMethod:) withObject:self.arry];
}
This is my parent controller
.m
-(void)childMethod:(NSArray *)params {
// some work
}
...
childVC *cVC = [[childVC alloc]init];
cVC.pVC = self;
But childMethod: is not getting called so I searched on internet and got this post
UINavigationControllers: How to pass value to higher (parent?) controller in stack?
I tried to create a weak reference but dont know how to use to make delegate pass data from child to parent?
Try this. Check the sample project attached
ParentViewController.h
#import <UIKit/UIKit.h>
#interface ParentViewController : UIViewController
- (void)passData:(NSString *)strText;
#end
ParentViewController.m
- (IBAction)btnGoToSecondView:(id)sender {
ChildViewController *secondVC = [[ChildViewController alloc] initWithNibName:#"ChildViewController" bundle:nil];
secondVC.delegate = self;
[self presentViewController:secondVC animated:YES completion:nil];
}
- (void)passData:(NSString *)strText {
NSLog(#"Data Passed = %#",strText);
}
ChildViewController.h
#import <UIKit/UIKit.h>
#import "ParentViewController.h"
#class ParentViewController;
#interface ChildViewController : UIViewController
#property(nonatomic, assign) ParentViewController *delegate;
#end
ChildViewController.m
- (IBAction)btnPassDataBack:(id)sender {
if([self.delegate respondsToSelector:#selector(passData:)]) {
[self.delegate passData:#"Hello"];
}
[self dismissViewControllerAnimated:YES completion:nil];
}
Sample Project
This is child controller.h
#protocol childProtocol <NSObject>
-(void)childMethod:(NSArray*)params;
#end
#property (strong, nonatomic) id<childProtocol>childDelegate;
#property (weak, nonatomic) parentVC *pVC;
.m
if([self.childDelegate respondsToSelector:#selector(childMethod:)]) {
[self.childDelegate performSelector:#selector(childMethod:) withObject:self.arry];
}
This is my parent controller.h
#import <UIKit/UIKit.h>
#import "ChildController.h"
#interface perentController : UIViewController < childProtocol >
.m
- (void)childMethod:(NSArray *)params {
// some work
}
EDITED :
And Dont Forget to add childViewOBJ.childDelegate = self; at the time of create ChildViewController's object. such like,
childVC *cVC = [[childVC alloc]init];
cVC.childDelegate = self;
cVC.pVC = self;
[self presentModalViewController:cVC animated:YES];
For More information about How to create/use of Protocol.
First of all, you are not checking for the same selector as you declared in your protocol declaration so it won't respond to that. You declared the method childMethod: whereas you are checking if your childDelegate responds to myMethod: selector which does not so it won't go into the if condition.
Also the parent view controller is missing the implementation the method childMethod: in its .m. Implement that in your parent view controller or it will crash because of not finding the exact selector definition.
Since you are using a UINavigationController, the parent view controller won't be lost till the child view controller exist so the childDelegate property must not be strong unless you intend to hold onto your delegate in child view controller for some reason.

Resources