Can't get property from another class - objective-c

I have a class RootViewController where I have a UIBarButtonItem declared. The method to display it is in another class FirstDetailViewController.
I am trying to access it in another class SecondDetailViewController, but it is always null. I tested with some other variables and they were null as well. Here's what I have:
RootViewController.h
#interface RootViewController : UITableViewController <UISplitViewControllerDelegate> {
}
#property (nonatomic, retain) UIBarButtonItem *rootPopoverButtonItem;
...
#end
RootViewController.m
#import "RootViewController.h"
#import "FirstDetailViewController.h"
#implementation RootViewController
#synthesize popoverController, splitViewController, rootPopoverButtonItem;
- (void)splitViewController:(UISplitViewController*)svc willHideViewController:(UIViewController *)aViewController withBarButtonItem:(UIBarButtonItem*)barButtonItem forPopoverController:(UIPopoverController*)pc {
NSLog(#"splitviewController will hide");
// Keep references to the popover controller and the popover button, and tell the detail view controller to show the button.
barButtonItem.title = #"Menu";
self.popoverController = pc;
self.rootPopoverButtonItem = barButtonItem;
UIViewController <SubstitutableDetailViewController> *detailViewController = [splitViewController.viewControllers objectAtIndex:1];
[detailViewController showRootPopoverButtonItem:rootPopoverButtonItem];
}
FirstDetailViewController.m
- (void)showRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem {
NSLog(#"show root popover button item");
// Add the popover button to the toolbar.
NSMutableArray *itemsArray = [toolbar.items mutableCopy];
[itemsArray insertObject:barButtonItem atIndex:0];
[toolbar setItems:itemsArray animated:NO];
[itemsArray release];
}
SecondDetailViewController.h
#import "RootViewController.h"
#class RootViewController;
#interface SecondDetailViewController : UIViewController <SubstitutableDetailViewController, UIScrollViewDelegate, UITextFieldDelegate, UITextViewDelegate> {
...
}
#property (nonatomic, retain) RootViewController *root;
#end
SecondDetailViewController.m
#import "SecondDetailViewController.h"
#implementation SecondDetailViewController
#synthesize root;
...
NSLog(#"view class : %#", [root.splitViewController class]);
[detailViewController showRootPopoverButtonItem:root.rootPopoverButtonItem];
...

You probably aren't setting the "root" property of SecondDetailViewController to the instance of RootViewController that you want to access the UIBarButtonItem for. Then you're reading an uninitialized instance of RootViewController in your SecondDetailViewController code, and the only reason you don't get an error is that Objective C silently ignores calls to methods on nil objects (in this case the rootPopoverButtonItem getter method, which the root.rootPopoverButtonItem is shorthand for).
If your instance of "RootViewController" is called "myRootViewController", then somewhere in your code you have to do something like:
SecondDetailViewController *mySecondDetailViewController = [[SecondDetailViewController alloc] init];
mySecondDetailViewController.root = myRootViewController;
Then you'll be accessing the copy of RootViewController that has the bar button you want.

Related

Calling Function from RootViewController

How to call a RootViewController function from FirstViewController?
I'm using Xcode 4.6 with storyboard.
RootViewController.m:
-(void)openMenu
{
...
}
FirstViewController:
- (IBAction)btnMenu:(id)sender {
RootViewController *root = [[RootViewController alloc] init];
[root openMenu]; // No visible #interface for 'RootViewController' declares the selector 'openMenu'
}
You have to declare the method in your header RootViewController.h. Example
- (void)openMenu;
A common practice for something like this is to use delegation. Your FirstViewController would have a delegate and then your RootViewController would set the delegate for the instance, and receive the information for the event.
FirstViewController.h
#protocol FirstViewDelegate;
#interface FirstViewController : UIViewController
#property (strong) id<FirstViewDelegate> delegate;
#end
#protocol FirstViewDelegate <NSObject>
- (void)openMenu;
#end
FirstViewController.m
- (IBAction)btnMenu:(id)sender {
[self.delegate openMenu];
}
MainViewController.h
#import "FirstViewController.h"
#interface RootViewController : UIViewController
<
FirstViewDelegate
>
MainViewController.m
-(IBAction)showFirstViewButtonClicked:(id)sender {
FirstViewController *firstViewController = [[FirstViewController alloc] init];
firstViewController.delegate = self;
[self presentViewController:firstViewController animated:YES completion:nil];
}
-(void)openMenu {
// this will be called when the btnMenu action is fired in the firstViewController
}

How do I use a button to get back to my first view

I am using a single view application template in xcode. I created the first view controller, and then added another with a new .m and .h and xib.
I can click a button IBAction, and get to my second view, however the code I am using for the "back" button wont take me back to my first view, everything crashes. I have included my code which seems to follow the tutorial I was using. Additionally I just control clicked my button and dragged the line to my IBAction in the .h to hook in the secondViewController buttons, which is what I did on the first view controller and it seems to work there.
If anyone can help that would be great!
//from my first view controller .h which works
-(IBAction) buttonPressedPayTable: (id) sender;
//from my first view controller.m which also works and gets me to the second view
-(IBAction) buttonPressedPayTable: (id) sender
{
SecondViewController *payTableView = [[SecondViewController alloc]
initWithNibName:#"SecondViewController" bundle:nil];
[self.view addSubview:payTableView.view];
}
//from my second view controller .h that will not get me back to the first view without crashing
#import <UIKit/UIKit.h>
#interface SecondViewController : UIViewController
{
}
-(IBAction) back: (id)sender;
#end
//from my second view controller .m which doesn't seem to work
#import "SecondViewController.h"
#implementation SecondViewController
-(IBAction) back: (id)sender
{
[self.view removeFromSuperview];
}
#end
use UINavigation controller
[self.navigationController popViewControllerAnimated:YES];
You might be better off using modal views. So instead of addSubView use:
[payTableView setModalPresentationStyle:UIModalPresentationFullScreen];
[payTableView setModalTransitionStyle:UIModalTransitionStyleFlipHorizontal];
[self presentModalViewController:payTableView animated:YES];
Then on the seconViewController back method:
[self dismissModalViewControllerAnimated:YES];
You can change the ModalTransitionStyle to the few that apple gives you :D
Hope this helps
You can use a navigation method for switching from one view controller to the other.
See the apple docs about view controllers
Don't add your second ViewController as a subview of the view.
Use a UINavigationController to add the new UIViewController to the view stack using [self.navigationController pushViewController:payTableView animated:YES];
Then you can either use the nav controllers back button, or use your own button with the code [self.navigationController popViewControllerAnimated:YES];
Alternately, you can use Storyboards and use a simple segue.
[payTableView.view removeFromSuperview];
i think you are removing the whole view .that is why app is crashing
You need to use delegate here:
in .h of first view declare a member variable :
#interface FirstViewControllerClassName: UIViewController
{
SecondViewController *payTableView;
}
#property (nonatomic, retain) SecondViewController *payTableView;
in .m :
#synthesize payTableView;
-(IBAction) buttonPressedPayTable: (id) sender
{
if (!payTableView)
payTableView = [[SecondViewController alloc]
initWithNibName:#"SecondViewController" bundle:nil];
payTableView.delegate = self;
payTableView.isFinishedSelector = #selector(removeView);
[self.view addSubview:payTableView.view];
}
- (void)removeView
{
[payTableView.view removeFromSuperview];
[payTableView release];
payTableView = nil;
}
//Just declare a member variable delegate in secondviewcontroller like:
#import <UIKit/UIKit.h>
#interface SecondViewController : UIViewController
{
id delegate;
SEL isFinishedSelector;
}
#property (nonatomic, assign) id delegate;
#property (nonatomic, assign) SEL isFinishedSelector;
-(IBAction) back: (id)sender;
#end
#import "SecondViewController.h"
#implementation SecondViewController
#synthesize delegate;
#synthesize isFinishedSelector;
-(IBAction) back: (id)sender
{
if ([self.delegate respondsToSelector:isFinishedSelector])
[self.delegate performSelector:isFinishedSelector];
}
#end

Objective C - iOS - UIWebView getting retained in ARC but Delegate methods are not being called

I am having an issue with ARC. It is not retaining the webview. The scenario is I have to send a webview from one viewcontroller to another one. The reason is when the user searches for something I want to take him to a new screen with some other options. (I have to use the same webview)
Here is the sample code: I have a ViewController1 which has a webview (I added it in the xib.) I am loading say google in it and once the user searches for something and when its done loading I have to take him to a new view controller and show the same webview in the new viewcontroller.
//ViewController1
#interface ViewController1 : UIViewController <UIWebViewDelegate>
#property (nonatomic, retain) UIWebView* testWebView;
#end
#implementation ViewController1
#synthesize testWebView;
- (void)viewDidLoad
{
[super viewDidLoad];
testWebView = [[UIWebView alloc]init];
testWebView.delegate = self;
[testWebView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"https://www.google.com"]]];
}
-(void)webViewDidFinishLoad:(UIWebView *)webView{
NSString *html = [testWebView stringByEvaluatingJavaScriptFromString:
#"document.body.innerHTML"];
if ([self.testWebView.request.url.absoluteString rangeOfString:#"output=search"].location != NSNotFound) {
ViewController2* newViewController = [[ViewController2 alloc] init];
[newViewController setTestWebView:self.testWebView];
[self.navigationController setViewControllers:[NSArray arrayWithObject:newViewController] animated:NO];
}
}
- (void)dealloc{
[self.testWebView stopLoading];
self.testWebView.delegate = nil;
self.testWebView = nil;
}
In the second view controller I am loading stackoverflow.com after a delay of 10 secs. The problem is it is loading stackoverflow fine, but it is not calling any of the delegate methods. Why?
#interface ViewController2 : UIViewController <UIWebViewDelegate>
#property (nonatomic, retain) UIWebView* testWebView;
#end
#implementation ViewController2
#synthesize testWebView;
- (void)viewDidLoad
{
[super viewDidLoad];
self.testWebView.delegate = self;
[self.view addSubview:testWebView];
[self performSelector:#selector(loadDifferentPage) withObject:nil afterDelay:10];
}
-(void)loadDifferentPage{
[self.testWebView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.stackoverflow.com/"]]];
}
-(void)webViewDidStartLoad:(UIWebView *)webView{
NSLog(#"%s", __PRETTY_FUNCTION__);
}
-(void)webViewDidFinishLoad:(UIWebView *)webView{
NSLog(#"%s", __PRETTY_FUNCTION__);
}
-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
NSLog(#"%s", __PRETTY_FUNCTION__);
return YES;
}
ViewController2 is retaining the webview but the delegate methods are not being called. Why?
Thanks
Sai
ViewController1 delloc method was causing the issue:
If I uncomment out self.textWebView.delegate = nil it works fine. The reason is first we are setting the webview for newViewController and later in dealloc of ViewController1 we are setting its delegate to nil.
- (void)dealloc{
[self.testWebView stopLoading];
if(self.testWebView.delegate == self)
self.testWebView.delegate = nil;
self.testWebView = nil;
}
First thing I noticed is you're not specifying the instance variable name when synthesizing a property. That's just asking for collisions. Here's an example of how that should look:
#interface ViewController1 : UIViewController <UIWebViewDelegate>
#property (nonatomic, strong) IBOutlet UIWebView* testWebView;
#end
#implementation ViewController1
#synthesize testWebView=_testWebView;
Also, I noticed in ViewController1 you used IBOutlet so everything is probably wired up in Interface Builder. Try making sure that you set the delegate property in Interface Bulider because you don't set it in the implementation. That would be why you're not receiving any messages.
ViewController2 looks like you set the delegate in code. The problem is, you DON'T have IBOutlet in front of the property. Normally this would mean that you simply setup the WebView in code, but in your example you do not ever create a new instance of a UIWebView control and assign it to self.testWebView. This means that if it does display on the page, it's because Interface Builder was used to create it. You couldn't set the delegate in code without using IBOutlet in front of the testWebView declaration so that's probably why it's not working in exmaple two.
#interface ViewController2 : UIViewController <UIWebViewDelegate>
#property (nonatomic, strong) UIWebView* testWebView; // Mising IBOutlet
#end
#implementation ViewController2
#synthesize testWebView;
- (void)viewDidLoad
{
[super viewDidLoad];
// missing any code that would create the webview [[UIWebView alloc] init]
self.testWebView.delegate = self; // You set the delegate in code here
[self.view addSubview:testWebView];
[self performSelector:#selector(loadDifferentPage) withObject:nil afterDelay:10];
}
Hope this helps, I'd have to see your full implementation to get more specific than this.

Objective-C: Calling class 2 instance from class1 [alloc init] way is not working

I've got the following method on a GameScreen.m file, with its own declaration - (void) drawNumbers on a GameScreen.h file:
//GameScreen.h
#import <UIKit/UIKit.h>
#interface GameScreen : UIView
{
IBOutlet UIButton *cell00;
}
- (void) drawNumbers;
- (IBAction) onCellClick:(id)sender;
#property (nonatomic, retain) IBOutlet UIButton *cell00;
#end
//GameScreen.m
#import "GameScreen.h"
- (void) drawNumbers
{
//testing if this works, so far it doesn't
[cell00 setTitle:#"Whatever" forState:UIControlStateNormal];
[cell00 setTitle:#"Whatever" forState:UIControlStateHighlighted];
}
I'm trying to call this method from my GameScreenViewController.m file, this way:
//GameScreenViewController.m
#import "GameScreenViewController.h"
#import "GameScreen.h"
...
- (void) viewDidLoad
{
GameScreen *aGameScreen = [[GameScreen alloc] init];
[aGameScreen drawNumbers];
[aGameScreen release];
[super viewDidLoad];
}
This is supposed to change the title of a button in a GameScreen.xib file where GameScreenViewController.m is the viewController and GameScreen class is the event handler where I get all the button clicks, timers running, etc. I am trying to call [drawNumbers] from [viewDidLoad] since I want the title to be changed when the screen is brought up front (screen management is done through the AppDelegate files).
The thing is, if I call drawNumbers instance from inside the same class through
//GameScreen.m
#import GameScreen.h
-(void) onButtonClick:(id)sender
{
//some other code
[self drawNumbers];
}
it works (as to say, nothing wrong with the code implementation or the graphic interface).
I've browsed through Apple Guide and tons of pages on the Internet, but I can't seem to find any light to this. Any further help (including answers as to where exactly find the answer in the ADG) would be really appreciated.
(Edited: here goes the AppDelegate code to flip to the specific view, just in case):
//myAppAppDelegate.h
#import <UIKit/UIKit.h>
#class myAppViewController, GameScreenViewController;
#interface myAppDelegate : NSObject <UIApplicationDelegate>
{
UIWindow *window;
myAppViewController *viewController;
GameScreenViewController *gameScreenViewController;
}
- (void) flipToGameScreen;
#property (nonatomic, retain) UIWindow *window;
#property (nonatomic, retain) GameScreenViewController *gameScreenViewController;
#end
//myAppAppDelegate.m
-(void) flipToGameScreen
{
GameScreenViewController *aGameScreenView = [[GameScreenViewController alloc] initWithNibName: #"GameScreen" bundle:nil];
[self setGameScreenViewController:aGameScreenView];
[aGameScreenView release];
[gameScreenViewController.view.frame = [[UIScreen mainScreen] applicationFrame];
[viewController.view removeFromSuperview];
[self.window addSubview:[gameScreenViewController view]];
}
Since your cell00 is to be set by a NIB it will be nil if you simply do [[GameScreen alloc] init]. It will only be set if the corresponding NIB is loaded (and a connection is actually set up).
If the cell can be accessed in your viewDidLoad, create a property on GameScreen and pass it through the property (or a dedicated initWithCell: or something).
If you have something like an IBOutlet GameScreen *aGameScreen; on your GameScreenViewController (and also established a connection to cell00 in the same NIB) you should access that instead.

objective C: Using a Delegate to call a function in parent class

I'm creating a 3 layer navigation popup controller and on the 3rd popup controller I have a delegate method to access dismissPopup method that is in the parent class. I can't seem to call it, my NSLog messages in the function in the parent class isn't even showing so I must be either using delegation wrong or I'm calling it incorrectly.
The 3 classes ParentViewController has a toolbar with a button that brings up the table view --> RegionViewController is the First table view controller with items --> ConusViewController is the 2nd table view controller that is pushed onto the navigation stack. I'm trying to call the method dismissPopover that is in the parent method with a delegation after the selection is clicked on so the whole popover goes away.
In the ConusViewController if the delegation had worked I would have seen "Method Accessed" from the function in the parent class. It doesn't show so I must be using delegation wrong.
Sorry for being so wordy on my post, I wanted to be complete on what I'm trying to do here. Thanks.
ParentViewController.h
#import <UIKit/UIKit.h>
#import "ConusViewController.h"
#interface EnscoWXViewController : UIViewController <ConusViewControllerDelegate> {
UIPopoverController *popoverController;
IBOutlet UIWebView *webImageDisplay;
ConusViewController *cViewController;
}
#property (nonatomic, retain) UIPopoverController *popoverController;
#property (nonatomic, retain) UIWebView *webImageDisplay;
#property (nonatomic, retain) ConusViewController *cViewController;
-(IBAction) buttonShowRegion:(id) sender;
#end
ParentViewController.m
#import "ParentViewController.h"
#import "RegionViewController.h"
#implementation ParentViewController
#synthesize cViewController;
-(IBAction) buttonShowRegion:(id) sender {
...
}
-(void)dismissPopover {
[popoverController dismissPopoverAnimated:YES];
printf("Method Accessed\n");
}
- (void)viewDidLoad {
cViewController = [[ConusViewController alloc] init];
cViewController.delegate = self;
[super viewDidLoad];
}
RegionViewController.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
switch (indexPath.row) {
case 0: {
ConusViewController *conusViewController = [[ConusViewController alloc] initWithNibName:#"ConusViewController" bundle:nil];
conusViewController.contentSizeForViewInPopover = CGSizeMake(320, 350);
[self.navigationController pushViewController:conusViewController animated:YES];
[conusViewController release];
break;
}
case 1: {
break;
}
}
}
ConusViewController.h
#import <UIKit/UIKit.h>
#protocol ConusViewControllerDelegate <NSObject>
#required
- (void)dismissPopover;
#end
#interface ConusViewController : UITableViewController {
NSMutableArray *conusItems;
id delegate;
}
#property (nonatomic, assign) id <ConusViewControllerDelegate> delegate ;
#end
ConusViewController.m
#import "ConusViewController.h"
#import "ParentWXViewController.h"
#implementation ConusViewController
#synthesize delegate;
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *itemRequested = [conusItems objectAtIndex:indexPath.row];
NSLog(#"logging: %#", itemRequested);
[delegate dismissPopover];
[itemRequested release];
}
Just before calling [delegate dismissPopover], check if delegate is actually set. It probably isn't.
I see in ParentViewController.m you create an instance of ConusViewController and set its delegate, but never display it. In RegionViewController.m you create another instance of ConusViewController without setting its delegate and that is the one that seems to be being displayed.
Not sure if I missed it, but I never see you set the delegate property in ConusViewController. That needs to be set to an instance of the object that is to be delegated to (the object that has dismissPopover implemented in it).