Access a TableViewController from another class - objective-c

I'm a beginner in objective-c and want to realize a simple GUI: A MyMainWindowController with a corresponding xib wich contains a table and a simple Add button.
#interface MyMainWindowController : NSWindowController
{
}
#end
The implementation code of the controller is nearly empty (pre-defined initWithWindow and windowDidLoad). The AddressTvc is defined like this:
#interface AddressTvc : NSObject <NSTableViewDataSource>
{
#private
IBOutlet NSTableView *myTableView;
NSMutableArray *list;
}
- (IBAction)add:(id)sender;
#end
This works fine. I can click on the Add button and a new row is inserted in the table.
It seems that the AddressTvc is created automatically (by the IB?) when the MyMainWindowController is visible. I want a reference in the code of MyMainWindowController to AddressTvc so I'm able to fill the table with some data retrieved by a background thread. This should be done by calling the - (IBAction)add:(id)sender; method.
I tried to create a AddressTvc inside the MyMainWindowController but then the object is initialized twice. I'm sure I have to wire it somewhere in the IB, but have no clue where to do this ...

Create an outlet in you MyMainWindowController class that can point to your table view controller class.
E.G.
#interface MyMainWindowController : NSWindowController
{
IBOutlet AddressTvc *myTVC
}
#end
Then simply control+drag from your file owner to the instance of the table view controller in interface builder and you can now access it in your window controllers code.

Related

NSObject as delegate for UITableView

I have a UITableView which is dragged into a UIViewController and a NSObject class. This NSObject class should serve as delegate and datasource to the tableview.
I tried creating an instance of NSObject and conformed delegate and datasource to the tableview. Datasource is working fine. But the cellForRowAtIndexPath: is never getting called and all i get is a EXC_BAD ACCESS and app just stops right there. But when I drag a object to UIViewController bottom pane and giving the class name to it and setting delegate and datasource, everything is working good and UITableView is displaying.
I don't know why this strange behaviour.
I have done this in the viewdidload of viewcontroller class.
customnsobject *custom=[customnsobject alloc]init];
tableview.delegate=custom;
tableview.datasource=custom;
create a parent id in your class h file like this
#property(nonatomic,retain) id parent;
and in your view controller just below the instance of nsobject you created do this
custom.parent=self;
I hope this will work

Simple passing of data through delegation in objective C

I'm using Xcode to write an app in objective c. I am trying to pass data from a container view controller to the parent view controller using delegation. I have successfully passed the data to the parent view controller, but all of the documentation sets what I have sent to the .h header file in the .m implementation file using viewDidLoad or viewDidAppear. I was wondering, since the view is already present, if there is a way to detect that data has been changed in a view and automatically run a method or code to update the view with the new information. Something along the idea of didReceiveNewData or didEditExistingValues (of course those arent real methods). Thank you for your help!
Edit: What I have done so far:
I want to pass the data from MainFeedTableViewController to MainFeedViewController (The first is in a container inside of the second). I want to set the title of the custom navigation bar in MainFeedViewController to something described in the MainFeedTableViewController.
In the MainFeedTableViewController.m (the view sending data) I have:
#import "MainFeedTableViewController.h"
#import "FeedViewController.h"
#interface MainFeedTableViewController ()
#end
#implementation MainFeedTableViewController
- (IBAction)swipeLeftDetected:(UIGestureRecognizer *)sender {
UIStoryboard *mc = self.storyboard;
FeedViewController *fv = [mc instantiateViewControllerWithIdentifier:#"FeedViewController"];
fv.navigationBarTitleToSet = #"HOPING TO SET TITLE TO THIS";
[self performSegueWithIdentifier:#"MainToLocalFeed" sender:self];
}
and some other unrelated stuff..
In the MainFeedTableViewController.h I have:
#import <UIKit/UIKit.h>
#interface MainFeedTableViewController : UITableViewController
#end
In the MainFeedViewController.m (the one receiving the data) I have:
#import "FeedViewController.h"
#interface FeedViewController () <UINavigationBarDelegate>
#property (weak, nonatomic) IBOutlet UINavigationBar *navigationBar;
#end
#implementation FeedViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)setNavigationBarTitle:(NSString *)navigationBarTitle{
self.navigationItem.title = navigationBarTitle;
}
And in the MainFeedViewController.h I have:
#import <UIKit/UIKit.h>
#interface FeedViewController : UIViewController
#property NSString *navigationBarTitleToSet;
#end
I want to run the setNavigationBarTitle method with either data from the .h (navigationBarTitleToSet) or just from the sending view controller, if possible to run a method with delegation. Thanks a ton and I hope this is possible :)
It turns out I needed to add a second navigation bar to account for the container view, allowing me to navigate around the current stack with the parentViewController method and then navigationItem.title. For anyone who happens to find this with a container, make sure you add one immediately after the embed segue. I'm still not sure if you can use methods through delegation, but I can't ponder any situations where it would be necessary anymore, due to viewDidLoad. Thanks to #Tander for the help!

implementing Target - Action pattern in custom view

I've created a custom view which inherits from NSView.
My goal is to notify my NSWindowControl which is associated with the window that contains the custom view, when the user click the the custom view.
I would like to implement this using the Action - Target pattern , just like a NSButton does.
So that I will be able connect the custom view with an action in the window controller using the Interface Builder.
Add the following to your custom view header file:
#interface MyCustomView : NSView
#property (weak, nonatomic) id userClickedTarget;
#property (assign, nonatomic) SEL userClickedAction;
#end
Synthesize the getter/setter in the custom view implementation file (this is actually optional with recent versions of Xcode/clang):
#synthesize userClickedTarget = _userClickedTarget;
#synthesize userClickedAction = _userClickedAction;
and to call the target/action within your code:
if (_userClickedTarget && _userClickedAction) {
[_userClickedTarget performSelector:_userClickedAction
withObject:self
afterDelay:0.0];
}
Note that using performSelector:withObject:afterDelay decouples the call from your view code and makes it run the next time the runloop is processed.

View not updating when a message is sent to its view controller

I am having problems updating a view when a message from another class is sent to a ViewController.
Basically I have an application with a single window where different custom views will be swapped out for another. I have an AppController Class that manages this and works fine:
#interface AppController : NSObject
#property (weak) IBOutlet NSView *ourView;
#property (strong) NSViewController *ourViewController;
- (IBAction)changeView:(id)sender;
- (IBAction)start:(id)sender;
- (void)changeViewContoller:(NSInteger)tag;
#end
When a new view is swapped out for another, the ourViewController property will be updated to point to that view's controller class. Every view controller class will have a method all named the same thing, for example "action". This method is supposed to change something on a view.
So the "start" method in AppController class will then call the "action" method on the ourViewController property. To do this I used the objc_msgSend() method:
objc_msgSend(self.ourViewController, action);
Here's the View Controller class definition:
#interface CountdownViewController : NSViewController
#property (weak) IBOutlet NSTextField *label;
- (IBAction)changeLabel:(id)sender;
- (void)start;
#end
I placed an NSLog() in the "action" method for each ViewController, to see if it was working, and it does, however the "action" method is also supposed to change a label's string value, but it does not. If anyone knows why the view is not being updated, that would be extremely helpful. Thanks!
the view is held weak?
TRY making it strong if you need to retain that pointer in this class
btw: ..also why do you objc_msgsend.... use performSelector

Modifying properties of a view controller form another view controller

In my project, there are two view controllers - let's say firstViewController and secondViewController. The second view controller has a button, and I want to make sure when the button gets pressed, the second view controller is telling somehow the first view controller - "hey, I got pressed, do something!", and it will do something, like changing a label. How is this possible to perform? Thanks in advance. Some code :
#interface firstViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *textLabel;
#end
#implementation firstViewController
#synthesize textLabel;
#end
#interface secondViewController : UIViewController
-(IBAction)buttonPressed;
#end
#implementation secondViewController : UIViewController
-(IBAction)buttonPressed{
// Hey, I got pressed! Set the text on textLabel to "OK"!
}
#end
This is a very simple case of delegation and protocol mechanism of objective-c..
have a look at this tutorial which will explain you how its done.. you can do this via notification also but that is not usually advised...(because notification is usually used when the receiver is unknown , like in the case of UIDeviceBatteryLevelDidChangeNotification you don't exactly know which view controller wants to know about this.)
I'd first consider what the button press means. Does it change the state of the model?
Say your model is an int, and the button increments it. The view controllers wouldn't message each other about that, they would just both observe the state of the model. (The one with the button could change the state, too).
Thinking about it this way, the solution probably isn't delegation. It's probably notification or KVO.
See the answer to this question: Passing data between two view controllers via a protocol
However, ask yourself if you really need a protocol here. If it is just between this classes or just about the question of accessing data of a class or sending information to a class then that is what the interface of a class is made for.
#interface firstViewController : UIViewController{
UILabel *textLabel; // I personally alway add IBOutlet here too, but I think that is not required.
}
#property (weak, nonatomic) IBOutlet UILabel *textLabel;
#end
And in SecondViewController.m:
#import "FirstViewController.h"
#implementation secondViewController : UIViewController
-(IBAction)buttonPressed{
// You will have to have a properly set instance variable firstViewController
[firstViewController.textLabel setText:#"OK"];
}
#end
So your second view controller needs to 'know' the first one. One way of achieving that is defining
FirstViewController *firstViewController;
as property and set it from wherever the second view controller is created and the first one is already known. How to do that exactly depends very much on the architecture of your app.