Accessing object defined in appDelegate - objective-c

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.

Related

IBInspectable property values not updating in xib

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.

Double click on row in NSTableView doesn't display the new view

I have an os x app that uses core data.
I have 3 .xib files in my app, those are:
1. MainMenu.xib
2. MasterTableViewController.xib
3. DetailViewController.xib
When started , app displays a view that has NSTableView with couple of records in it.
I name that view MasterTableViewController
I want when user double click on the row, to hide the "master" view and to display my "detail" view. I named that view DetailViewController.
When double clicked on the row in the NSTableView in the "master" view,nothing happen, "master" view remains visible. What I want is "master" view to dissapear, and "detail" view to appear.
Here is the code that I have right now, and more explanations follows:
AppDelegate.h
#import <Cocoa/Cocoa.h>
#interface AppDelegate : NSObject <NSApplicationDelegate>
#property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
#property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
#property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#property (nonatomic,strong) NSViewController *mainAppViewController;
#property (weak) IBOutlet NSView *mainAppView;
- (void)changeViewController:(NSInteger)tag;
#property (weak) IBOutlet NSTableView *websitesTableView;
- (void)tableViewDoubleClick:(id)nid;
#end
AppDelegate.m
#import "AppDelegate.h"
#import "MasterTableViewController.h"
#import "DetailViewController.h"
#interface AppDelegate ()
#property (weak) IBOutlet NSWindow *window;
- (IBAction)saveAction:(id)sender;
#end
#implementation AppDelegate
NSString *const masterTable = #"MasterTableViewController";
NSString *const detail = #"DetailViewController";
-(void)awakeFromNib {
[_websitesTableView setTarget:self];
[_websitesTableView setDoubleAction:#selector(tableViewDoubleClick:)];
}
- (void)tableViewDoubleClick:(id)nid {
NSInteger rowNumber = [_websitesTableView clickedRow];
NSTableColumn *column = [_websitesTableView tableColumnWithIdentifier:#"websiteUrl"];
NSCell *cell = [column dataCellForRow:rowNumber];
NSInteger tag = 2;
[self changeViewController:tag];
}
- (void)changeViewController:(NSInteger)tag {
[[_mainAppViewController view]removeFromSuperview];
switch (tag) {
case 1:
self.mainAppViewController = [[MasterTableViewController alloc]initWithNibName:masterTable bundle:nil];
break;
case 2:
self.mainAppViewController = [[DetailViewController alloc]initWithNibName:detail bundle:nil];
break;
}
[_mainAppView addSubview:[_mainAppViewController view]];
[[_mainAppViewController view] setFrame:[_mainAppView bounds]];
[[_mainAppViewController view] setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// automatically run the master table view controller
NSInteger tag = 1;
[self changeViewController:tag];
}
Now, some of you may wondering, where is the rest of the code. I have ommited the boiler plate code for the core data below in the AppDelegage.m, since it is unchanged. I used binding to make my NSTableView to work and to display my records, so MasterTableViewController.h and .m files are empty, and same is true for the DetailViewController.h and .m file.
Important note - What i can't understand here: If I change the tag in 2 in the applicationDidFinishLaunching method, detail view is displayed normally, but if i switch it back on 1, and then double click on the row, "master" view (with the NSTableView) remains visible, and nothing happen (views are not swapped)
Anyone can help me to find out what is wrong with my code?
Regards, John
You apparently had a second instance of your AppDelegate class instantiated in the MasterTableViewController.xib file. There should be only one AppDelegate instance and that's the one in MainMenu.xib. So, it shouldn't be in MasterTableViewController.xib.
One of the instances was receiving the double-click action method from the table, but the other one was the one with the outlet to the main window.
You need(ed) to get rid of the second instance and find another way to access the app delegate from the MasterTableViewController.

UISwitch, if/else statement to filter TableView

So I'm creating a Settings view (SettingsViewController) for my app, and the view contains 5 switches. I'm looking to accomplish the following:
if switch is on, filter TableView to only display items that contain 'Arthritis'. if switch is off, display all items.
Note: the TableView is located on another view (ViewController).
Now even though I've imported ViewController.h onto my SettingsViewController.m file, it's telling me that StrainTableView is unidentified. Any idea as to why? See code below (you can ignore the PickerView references).
SettingsViewController.h
#interface SettingsViewController : UIViewController {
IBOutlet UISwitch *ArthritisSwitch;
IBOutlet UIView *CancerSwitch;
IBOutlet UISwitch *HIVSwitch;
IBOutlet UISwitch *InsomSwitch;
IBOutlet UISwitch *MigSwitch;
IBOutlet UILabel *mylabel;
NSArray *arthritisResults;
NSArray *Strains;
}
-(IBAction)switchtheswitch:(id)sender;
#property (nonatomic, retain) NSArray *arthritisResults;
#end
SettingsViewController.m
#import "SettingsViewController.h"
#import "ViewController.h"
#interface SettingsViewController ()
#end
#implementation SettingsViewController
#synthesize arthritisResults;
-(IBAction)switchtheswitch:(id)sender; {
if (ArthritisSwitch.on) {
NSPredicate *ailmentPredicate = [NSPredicate predicateWithFormat:#"title ==[c] 'Arthritis'"];
arthritisResults = [Strains filteredArrayUsingPredicate:ailmentPredicate];
// Pass any objects to the view controller here, like...
[StrainTableView setSearchResults: [arthritisResults copy]];
NSLog(#"%#", arthritisResults);
}
else {
[Strains count];
}
}
ViewController.h
#import "PickerViewController.h"
#interface ViewController : UIViewController <PickerViewControllerDelegate, UITableViewDataSource,UITableViewDelegate>
{
NSArray *searchResults;
// NSArray *Strains;
NSMutableData *data;
NSMutableArray *dataArray;
NSArray *Strains;
}
#property (nonatomic, strong) NSMutableArray * favoritesArray;
#property (nonatomic, retain) NSArray *searchResults;
#property (strong, nonatomic) IBOutlet UITableView *StrainTableView;
#end
Just importing a class does not allow you to use a property from that class. You need to get an instance of the ViewController class (let's call it vc for example), and then use it like so:
[vc.StrainTableView setSearchResults: [arthritisResults copy]];
How you make that instance of ViewController depends on the structure of your app. You probably don't just want to alloc init one, but get a reference to one that you already have.
BTW, your code would be easier to read and understand if you conform to the naming convention of using lowercase letters to start properties and methods (and capitals for classes).

PhoneGap AppDelegate MainViewController

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.

IBOutlet in ARC releases and sets to nil. How to avoid this? objective c

I'm new to ARC and Storyboarding. I've set IBOutlet to UITableView from my UIViewController.
After some time my IBOutlet sets to nil and I can't reload it from other classes.
Here is my dataTable IBOutlet:
#property (weak, nonatomic) IBOutlet UITableView *dataTable;
At the start dataTable is not nil, but not when I try to access it from another class (via appDelegate). How to solve this problem?
UPDATE
I call this method from my UIViewController
[appDelegate.myClass loginWithUserName:loginField.text andPassword:pwdField.text];
When it's done, and I have data to show, I call this code from loginWithUserName method:
MyViewController *controller = [[AppDelegate sharedStoryboard] instantiateViewControllerWithIdentifier:#"MyViewController"];
[controller audioLoaded];
And here is that method in my UIViewController, wich reloads data
-(void) audioLoaded
{
//it is nil here
[self.dataTable reloadData];
}
Set the property to strong retain the object:
#property (strong, nonatomic) IBOutlet UITableView *dataTable;
It's not good practice to access a UITableView from another view controller though..
EDIT:
You shoul reconsider the whole approach, by moving that logic from your appdelegate to a dedicated class that will perform the login. You can create a simple protocol that the UIViewController with the table can implement, then, when calling the login method, pass a reference to the current viewcontroller, something like
loginWithUserName:andPassword:andCaller:(id<LoginDelegate>)sender
Where LoginDelegate is something on this line:
#protocol LoginDelegate
- (void)audioLoaded;
#end
In this way you can just call
[sender audioLoaded];