I setup a PhoneGap application and dug around some of the code. Under AppDelegate there is the following object:
#property (nonatomic, strong) IBOutlet CDVViewController* viewController;
However, further down there is this line:
self.viewController = [[MainViewController alloc] init];
What does that line actually do, as viewController is a CDVViewController object, however it now seems to be saying, or at least converting it to a MainViewController object.
Also MainViewController inherits CDVViewController so whats the point should it not begin as a MainViewController like:
#property (nonatomic, strong) IBOutlet MainViewController* viewController;
It doesn't begin as #property (nonatomic, strong) IBOutlet MainViewController* viewController so that when self.viewController responds to a message's selector, self.viewController can be either class CDVViewController or MainViewController, depending on which responds to the selector at runtime.
This is called polymorphism. You can take a look at this or this.
Related
I'm running into a minor complication using IBInspectable properties and not sure if it might have something to do with my xibs and xib usage. I'm trying to reuse a custom control between multiple view controllers. The control is a custom tab manager:
The IBInspectable Attributes are configured in this xib as: First, Second, Third.
Here is the corresponding code for the header file.
IB_DESIGNABLE
#interface TabContainerView : NSView
#property (nonatomic, strong) IBOutlet NSView *view;
#property (weak) IBOutlet TabContentView *contentView;
#property (weak) IBOutlet TabView *firstTab;
#property (weak) IBOutlet TabView *secondTab;
#property (weak) IBOutlet TabView *thirdTab;
#property (nonatomic, strong) IBInspectable NSString *tabOneText;
#property (nonatomic, strong) IBInspectable NSString *tabTwoText;
#property (nonatomic, strong) IBInspectable NSString *tabThreeText;
#end
#import "TabContainerView.h"
#interface TabContainerView ()
#property (nonatomic, strong) NSMutableArray *tabsArray;
#property (nonatomic, assign) NSInteger selectedTabIndex;
#property (weak) IBOutlet NSTextField *tabOneTextField;
#property (weak) IBOutlet NSTextField *tabTwoTextField;
#property (weak) IBOutlet NSTextField *tabThreeTextField;
#end
#implementation TabContainerView
#pragma mark Init
- (id)initWithFrame:(NSRect)frameRect {
NSString* nibName = NSStringFromClass([self class]);
self = [super initWithFrame:frameRect];
if (self) {
if ([[NSBundle mainBundle] loadNibNamed:nibName
owner:self
topLevelObjects:nil]) {
[self configureView];
}
}
return self;
}
#pragma mark Configure View
- (void)configureView{
[self.view setFrame:[self bounds]];
[self addSubview:self.view];
self.tabOneTextField.stringValue = self.tabOneText;
self.tabTwoTextField.stringValue = self.tabTwoText;
self.tabThreeTextField.stringValue = self.tabThreeText;
}
#end
This works fine in the TabContainerView.xib without issue. Now when I attempt to use this control in two different view controllers, I run into problems. Both of my view controllers are also loaded from Xibs.
In view controller 1 I have something like this:
In view controller 1 I've subclassed the custom view to the TabContainerView subclass which works just fine when I run the application. I've also changed the text to be specific for this view controller. List, Map, Filter are the IBInspectable property values for view controller one. In view controller 2 (not shown), I've done the exact same thing, however different IBInspectable property values specific for view controller 2. However, when I run the application the values never update and always stay as First, Second, and Third. I'm not sure if there is something I'm doing that's causing this problem but any help or tips would be appreciated. (IBDesignable seems to give me a lot of warnings where it breaks and not sure if maybe it's just loading the last saved value for the xib.)
Have you imported #import "TabContainerView.h" in controller 2 .h file.
I am just learning and trying to put forth some of the knowledge with objective c and cocoa. I have a little program that has a login screen which then displays a main menu. On the main menu view, there is a button that should load a view to be able to add some data to the app. When I click on the button, it doesn't fire the IBAction but throws an error
EXC_BAD_ACCESS [StartMenuViewController performSelector:withObject:]: message sent to deallocated instance 0x6080195e9f90
I know that it is because there is an object that is not instantiated when the message is being sent, but I cannot find out why. Sorry for the code and the novice level here is the main menu view controller StartMenuViewController.m file:
#import "StartMenuViewController.h"
#import "AppDelegate.h"
#import "MasterViewController.h"
#interface StartMenuViewController ()
#end
#implementation StartMenuViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do view setup here.
}
-(IBAction)showStrainView:(id)sender{
AppDelegate *delegate = nil;
delegate = (AppDelegate *)[[NSApplication sharedApplication] delegate];
MasterViewController *addStrainView = [[MasterViewController alloc] initWithNibName:#"MasterViewController" bundle:nil];
[delegate swapView:self.view toView:addStrainView.view];
}
#end
here is the StartMenuViewController.h
#import <Cocoa/Cocoa.h>
#interface StartMenuViewController : NSViewController
#property (weak) IBOutlet NSButton *showStrainViewButton;
#end
Here is the AppDelegate.h
#import <Cocoa/Cocoa.h>
#class loginView, MasterViewController,StartMenuViewController;
#interface AppDelegate : NSObject <NSApplicationDelegate>{
loginView *loginView;
MasterViewController *masterViewController;
}
#property (assign) IBOutlet NSWindow *window;
#property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
#property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
#property (strong) loginView *loginView;
#property (strong) MasterViewController *masterViewController;
#property (strong) StartMenuViewController *starMenuViewController;
-(void)swapView:(NSView *)view1 toView:(NSView *)view2;
#end
Here is the AppDelegate.m
#import "AppDelegate.h"
#include "MasterViewController.h"
#import "ScaryBugDoc.h"
#import "Strains.h"
#import "loginView.h"
#interface AppDelegate()
#end
#implementation AppDelegate
#synthesize managedObjectContext = _managedObjectContext;
#synthesize managedObjectModel = _managedObjectModel;
#synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
#synthesize loginView;
#synthesize masterViewController;
#synthesize starMenuViewController;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// 1. Create the master View Controller
self.loginView = [[loginView alloc] initWithNibName:#"loginView" bundle:nil];
// 2. Add the view controller to the Window's content view
[self.window.contentView addSubview:self.loginView.view];
self.loginView.view.frame = ((NSView*)self.window.contentView).bounds;
}
-(void)swapView:(NSView *)view1 toView:(NSView *)view2{
//[view1 removeFromSuperview];
[self.window.contentView addSubview:view2];
view2.frame = ((NSView*)self.window.contentView).bounds;
}
#end
If you need the loginView.h and loginView.m files I can add them as well. I would appreciate any and all help. Thanks in advance
The problem is here:
MasterViewController *addStrainView = [[MasterViewController alloc]initWithNibName:#"MasterViewController" bundle:nil];
[delegate swapView:self.view toView:addStrainView.view];
You don't keep a reference to the MasterViewController so it gets deallocated even though its view is kept around. Now anytime the view tries to access methods from the view controller, things fail.
You should make addStrainView a child view controller of self in the above code so the view controller sticks around as long as its view.
How can I access to ViewController property from another class ?
(the ViewController was created by XCode)
this is code of ViewController.h:
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#interface ViewController : UIViewController{
AppDelegate *appDelegate; //il delegate disponibile per tutta la classe
int numPag; //indice array (sulle pagine html da visualizzare)
NSString *path;
NSURL *baseURL;
NSString *file;
NSString *contentFile;
}
- (IBAction)sottrai:(id)sender;
- (IBAction)aggiungi:(id)sender;
#property (strong, nonatomic) IBOutlet UILabel *valore;
#property (strong, nonatomic) IBOutlet UIWebView *web;
#end
thanks!
[EDIT]
I use Xcode 4.3.2 and the code of AppDelegate.m not find something like:
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
Now, I put in the method didFinishLaunchingWithOptions:(into AppDelegate.m) this code:
viewController = [[UIViewController alloc] initWithNibName:#"ViewController" bundle:nil];
[viewController.web loadHTMLString:contentFile baseURL:baseURL];
adding in the file AppDelegate.h the variable viewController:
#import <UIKit/UIKit.h>
#interface AppDelegate : UIResponder <UIApplicationDelegate>{
NSArray *pageInItalian;
NSArray *pageInEnglish;
UIViewController *viewController;
}
#property (strong, nonatomic) NSArray *pageInLanguage;
#property (strong, nonatomic) UIWindow *window;
#end
I did it correctly? the error is: Property 'web' not found on object of type 'UIViewController *'
I think this post might answer your question
How can I access variables from another class?
You need to make your variable accessible from foreign classes (with #property and #synthesize) and then your foreign class need to know your instance of ViewController
[EDIT]
In your AppDelegate.m, there must be a line like this one :
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
This is where your ViewController is instantiate. From there, you can access every property of your ViewController.
[EDIT]
You need to add the following at the beginning of your implementation
#implementation ViewController
#synthesize web;
So heres my issue. I assume its a simple one but i just cannot figure out why this is not working.
I need to access Outlets (UITextField, UITableView, UIActivityIndicatorView, etc.) in one class (RootViewController) from a different class (ServiceController).
I have this currently (only showing whats need) :
RootViewController.h
#interface RootViewController : UIViewController{
UITextField *textField;
}
#property (nonatomic, retain) IBOutlet UITextField *textField;
- (void)startService;
#end
RootViewController.m
#implementation RootViewController
#synthesize textField;
- (void)startService{
ServiceController *service = [[ServiceController alloc] init];
[service start];
[service release];
}
#end
ServiceController.h
#class RootViewController;
#interface ServiceController : NSObject{
}
#property (nonatomic, retain) IBOutlet RootViewController *rootViewController;
- (void)start;
#end
ServiceController.m
#import "RootViewController.h"
#implementation ServiceController
#synthesize rootViewController;
- (void)start{
[((RootViewController*)rootViewController).textField setText:#"HELLO !"];
NSLog(#"CALLED !");
}
#end
I do not see why this is not working, i use the same method to do the same thing from the RootViewController to the DetailViewController and it works fine. I checked to see if there were any other declaration in the detail/root controllers to allow that to work but i did not notice any.
PS: everything is being called successfully and "CALLED !" is being logged, just whatever i do to the outlet(s) has no effect.
Your ServiceController needs to have its rootViewController property set. You can either do this in an XIB file or explicitly in code:
myServiceController.rootViewController = myRootViewController;
It looks like you didn't set the rootViewController.
Try adding :
ServiceController *service = [[ServiceController alloc] init];
// set the property here
[service setRootViewController:self];
[service start];
[service release];
I'm recoding a splitview controller app I did so the table view isn't always on the side.
I have my appDelegate, a ViewController, the table view and another view called DetailViewController.
I'm declaring a instance of the DetailViewController in my appDelegate.h file
#class SalesMate2ViewController;
#class DetailViewController;
#class Categories;
#interface SalesMate2AppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
SalesMate2ViewController *viewController;
DetailViewController *dvc;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet SalesMate2ViewController *viewController;
#property (nonatomic, retain) DetailViewController *dvc;
#end
In the viewController.m I'm creating the actual instance of dvc
dvc = [[DetailViewController alloc] initWithNibName: #"DetailViewController" bundle: nil]];
But when I try to access the dvc instance in the table view it appears I'm dealing with an new object, data doesn't persist or shows null when logged. Everything compiles and runs but code accessing dvc in the table view doesn't work.
In the viewController and table view (h and m files) I'm including the dvc as a #property and #synthesize. Is that what I'm doing wrong? But when I take those out I get warnings saying dvc is undeclared.
I get the feeling I'm dealing with two instances of dvc but I don't know how to fix it. Any hints?
Thanks,
Steve
Indeed, in your viewController you are allocing a new instance of dvc, which means anything done in one, won't carry over in the other.
Make an attacher method in yourSalesMate3ViewController and call that from the app delegate. Like so:
SalesMate2ViewController.h
-(void)attachDetailVC :(DetailViewController*) myDvc;
SalesMate2ViewController.m
-(void)attachDetailVC :(DetailViewController*) myDvc
{
self.dvc = myDvc;
}
And call it from your SalesMate2AppDelegate
self.dvc = [[DetailViewController alloc] initWithNibName: #"DetailViewController" bundle: nil]]
[viewController attachDetailVC:self.dvc];
Now they will both reference the same and either class can manipulate it.