Loading multiple tableviews in a UIView (UIView Controller) - ios

I've been searching all throughout the internet for assistance, however there has been little to no solutions to my issue at hand. My project that im trying to get a gasp on is somewhat unique (UI is not exactly following the typical norms).
Current Development Enviroment:
xcode 4
storyboards instead of nibs
Below is a diagram of what i am trying to accomplish -- all within a UIView Controller:
UIView is the light grey background
UITableView 1 - this is a static (or it can be dynamic, thats another challenge) UITableview which will hold different numeric
values for calculation
UITableView 2 - this is a UITableview which will hold calculated results every time it is run.
UIImageView 1 - this is a calculated image example (I have that figured out)
Im sure experienced developers are fully aware of my issue, and or what im about to ask. I understand that a static UITableView is required to be in a tableview controller, but I need to display both the UItableView's at the same time which means it has to be within a UIView.
I can make the interface look the way I need it to through the IB however when trying to compile and build I receive the error that requires the UITableView's to be within a UITableViewController and not a UIView Controller. I have seen many examples using a master-detail layout, but the only stipulation is that this UITableview NEEDS to be displayed 100% of the time when in this view.
So basically, I am asking for direction... but a code example never hurt either! Thank you 100x's over!
-Jonathan

UITableViewController is just a specialized UIViewController specially designed to display full screen UITableViews. It is (quite) equivalent to use an UITableViewController subclass or an UIViewController <UITableViewDataSource, UITableViewDelegate> subclass to manage a tableview.
So even if UITableViewController has some more spiecialized behaviors (automatically creates the UITableView if it does not exists, scrolls it automatically to display the keyboard, sets itself as the delegate and dataSource of the unique UITableView it manages, etc), you can use a standard UIViewController to manage a UITableView and be its dataSource to fill it.
That's even a way to manage a tableview that is not taking the full screen (as UITableViewController expects its view property to directly be the UITableView it manages, not a subview of its main view or whatever, and thus expects the UITableView to take the whole screen, contrary to using an UIViewController that has an UITableView as a custom-sized subclass of its view)
So in your case, you can have an UIViewController that has two IBOutlets, one for each tableView, and that unique UIViewController can be the dataSource (and delegate) of both the UITableViews. That's not a problem. Just be careful then in your datasource methods to distinguish if you are returning data for the first or the second UITableView to feed the correct tables each time.
#interface MyViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
#property (nonatomic, retain) IBOutlet UITableView* masterTableView;
#property (nonatomic, retain) IBOutlet UITableView* detailsTableView;
#end
#implementation MyViewController
#synthesize masterTableView = _masterTableView;
#synthesize detailsTableView = _detailsTableView;
// Proper memory mgmt not shown here:
// - don't forget to set self.masterTableView and self.detailsTableView to nil in viewDidUnload
// - and to release _masterTableView and _detailsTableView in your dealloc method
-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
UITableViewCell* cell;
if (tableView == self.masterTableView)
{
static NSString* kMasterCellIdentifier = #"MasterCell";
cell = [tableView dequeueReusableCellWithIdentifier:kMasterCellIdentifier];
if (!cell)
{
cell = [[[UITableViewCell alloc] initWithReuseIdentiier:kMasterCellidentifier] autorelease];
// do some configuration common to all your master cells
}
// configure the rest of your cell for each property that is different from one cell to another
}
else if (tableView == self.detailsTableView)
{
// Do exactly the same principle, but for the cells of your "details" TableView
}
return cell;
}

Related

UICollectionView Datasource Methods

UICollectionView has some built-in datasource methods, such as the "cellforItemAtIndexPath" method and the "numberofitemsinsection" method. If I understand correctly, these methods are called after viewDidLoad() completes. However, for my purposes, I want to be able to exactly control the point in time in which these methods are called. How can I do that?
The reason is that I am loading loading some images and I want to finish the task of loading before these methods are called.
It sounds like you don't want to show the collection until the images are downloaded, is that right? Does returning 0 for the number of items until the images finish downloading work? I don't have my Mac with me, or I'd test this before posting.
Disconnect the collectionView datasource and delegate connected to the controller from storyboard. Then set them in the code once you needed.
First connect the collectionView outlet to the interface section.
#interface YourViewController : UIViewController <UICollectionViewDataSource, UICollectionViewDelegate>
#property (weak, nonatomic) IBOutlet UICollectionView *collectionView;
So once your images are loaded, call this method:-
self.collectionView.delegate= self;
self.collectionView.dataSource= self;
[self.collectionView reloadData];

Should I store data in my custom UITableView?

I have 2 viewControllers that each contains one UITableView among other subviews. The 2 UITableViews have the same section structure and cell types, but the data source is different.
So I decided to extract this UITableView into a custom UITableView. The custom UITableView implements methods like tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath, and is its own data source and delegate. The viewController only provides data.
The question is I can't figure out which is the best way for viewControllers to provide data. I can think of 2 ways:
first way
in MyCustomTableView.h:
#protocol MyCustomTableViewDataProvider <NSObject>
- (NSArray*)dataArray;
#end
#interface MyCustomTableView : UITableView
#property (nonatomic, weak) id<MyCustomTableViewDataProvider> dataProvider;
#end
The viewController should implement this protocol:
- (NSArray*)dataArray {
return self.dataArray;
}
And in MyCustomTableView.m I use it like:
NSArray* dataArray = [self.dataProvider dataArray];
second way
in MyCustomTableView.h:
#interface MyCustomTableView : UITableView
#property (nonatomic, weak) NSArray* dataArray;
#end
Every time when there's a change in data, the viewController should inform the custom TableView to update its data:
self.customTableView.dataArray = self.dataArray;
And in MyCustomTableView.m I use it like:
self.dataArray
It seems that the second way could save some code, but I heard that you shouldn't store data in views because it violates the MVC principle. Could you please give me some advice? Many thanks!
IMHO, I wouldn't subclass any UIView unless it's absolutely necessary. Both TableViews and Collections provide protocols to control their behavior correctly.
If I were you, in order to keep the ViewController clean and short, I would create a custom NSObject implementing both UITableViewDelegate and DataSource protocols. This class would be in charge of providing the style of cells and sections (that is shared in those 2 table views) and also the data source. Of course, this object must have a property referencing its TableView.
The ViewController would only be in charge of triggering data retrieval whenever is needed. That data should be passed to that custom NSObject, which would be in charge of updating the table view.
BTW, this object could even be added through InterfaceBuilder.
It's a bit old, I know, but you could check :Lighter VC It's just a step forward towards MVVM.

All UITableCells disappear when tapping on UITableView in iOS 7

I am having a problem with my UITableView in iOS7. Initially, the data loads in just fine, and I get output in my console that proves that the cells are speaking to the data source correctly, but as soon as I tap anywhere on the table, the cells disappear and the table goes blank. The height of the cells in the empty UITableView seem to be honoring the height my custom prototype cell (410px), but all the data in the cells vanish, and the empty table view acts like it only has one cell in it (like its default state before it gets hooked up to the delegate).
I am using Storyboards for this app.
To get a little context, this app is similar to the iphone Instagram app, and I am using this application as way to learn iOS 7 development. I have been banging my head up against a wall trying to solve this issue, and I can't find any online resources that can help me solve this, so I wanted to ask all the smart peeps on Stack Overflow.
I have prepared a graphic that helps you see the problem
higher resolution version here
Here is my TableViewController code:
#interface PA_PhotoTableViewController ()
#property (nonatomic, copy) NSArray *photos;
#end
#implementation PA_PhotoTableViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.photos = [[PA_PhotoStore sharedPhotoStore] allPhotos];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [[[PA_PhotoStore sharedPhotoStore] allPhotos] count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
PA_PhotoCell *cell = [tableView dequeueReusableCellWithIdentifier:#"PhotoCell" forIndexPath:indexPath];
PA_Photo *photo = (self.photos)[indexPath.row];
cell.photoTitle.text = photo.title;
cell.photoOwnerName.text = [NSString stringWithFormat:#"%#", photo.owner];
cell.photoLikes.text = #"99";
// Photo Image URL
NSURL *photoImageURL = [NSURL URLWithString:photo.image_full_url];
[cell.photoImage sd_setImageWithURL:photoImageURL placeholderImage:[UIImage imageNamed:#"lightGraySpinningLoader.gif"]];
// Photo Owner Image
[cell.photoOwnerImage sd_setImageWithURL:photoImageURL placeholderImage:[UIImage imageNamed:#"lightGraySpinningLoader.gif"]];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// This code never gets called when I try to tap on a cell
NSLog(#"A row was selected");
}
- (void)dealloc {
NSLog(#"dealloc called in PA_PhotoTableViewController");
}
and here is the custom cell code PA_PhotoCell (consolidated .h & .m files):
#interface PA_PhotoCell : UITableViewCell
#property (nonatomic, weak) IBOutlet UIImageView *photoImage;
#property (nonatomic, weak) IBOutlet UILabel *photoTitle;
#property (nonatomic, weak) IBOutlet UILabel *photoOwnerName;
#property (nonatomic, weak) IBOutlet UIImageView *photoOwnerImage;
#property (nonatomic, weak) IBOutlet UILabel *photoLikes;
#property (nonatomic, weak) IBOutlet UILabel *photoTimestamp;
#property (nonatomic, weak) IBOutlet UILabel *photoComments;
#end
#implementation PA_PhotoCell
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
NSLog(#"in set selected");
}
-(void)setHighlighted:(BOOL)highlighted {
NSLog(#"in set highlighted");
}
You can see a few NSLog() calls to help me see if anything is getting called.
Where am I going wrong? The end goal is to click on one of the TableViewCell instances and launch a UINavigationController, I know how to do that, but I can't move on to that step until I figure out why my UITableView won't scroll, and why it disappears when I click on it!
EDIT: After much testing, debugging and experimentation, I have been able to conclude that the problem is actually not with the UITableView at all, and it is, in fact, a problem with how the UITableView is being loaded into its parent view. I still haven't found a solution to my problem, but I am getting closer to finding the cause. Here is what I have discovered:
First, when any of the UIButtons at the bottom of the screen are tapped (see photo reference), it loads the relevant instance of UIViewController into a UIView called placeholderView. When I run my problematic UITableView OUTSIDE of this UIView (where the UITableViewController is acting on its own, not embedded within another UIView) then the table works perfectly, it scrolls, it revives click events, and so on. So as soon as I load the UITableView into the UIView, the UITableView becomes unresponsive (it doesn't scroll or receive tap events) and any attempt to interact with it, the UITableView goes completely blank. My debugging session concludes that the NSArray *photos never gets reset to nil, or manipulated in anyway, the table just goes blank.
So does anyone have any ideas on what would cause a UITableView to do this when being loaded into a generic UIView? All the other views that get loaded into this generic UIView are responsive, and behave as expected. Its just this UITableView that is giving me problems.
If you review the graphic I attached to this post (above), you will see that I am using what appears to be a UITabBarView, but it is, in fact, just a generic view with UIButtons inside. The reason I decided to craft my own "UITabBarView look-alike" instead of using the ready-made UITAbBarView class was because I wanted to give custom functionality to the "menu" button on the bottom left (I want a nice UIView to slide in from the left, and stop about 60 pixels from the right of the screen when the "menu" button is tapped, and I can't figure out how to customize the behavior of the UITabBarView, so I opted for this approach.
Here is the code that is actually loading the UITableViewController into the subview (via a CustomStoryboardSegway):
// PA_HomeViewCustomStoryboardSegue.m
#import "PA_HomeViewCustomStoryboardSegue.h"
#import "PA_HomeViewController.h"
#implementation PA_HomeViewCustomStoryboardSegue
// to create a custom segue, you have to override the perform method
-(void)perform {
// get the source and destination view controllers
PA_HomeViewController *segueSourceController = (PA_HomeViewController *)[self sourceViewController];
UIViewController *destinationController = (UIViewController *)[self destinationViewController];
for (UIView *view in segueSourceController.placeholderView.subviews){
[view removeFromSuperview];
}
segueSourceController.currentViewController = destinationController;
[segueSourceController.placeholderView addSubview:destinationController.view];
}
#end
and here is the header file for my PA_HomeViewController (the view the contains the "placeholderView" which is the target view that loads the various UIViewControllers after the user has tapped the UIButtons at the bottom of the view (similar to a TabBarView) :
#interface PA_HomeViewController : UIViewController
#property (weak, nonatomic) IBOutlet UIView *placeholderView;
#property (weak, nonatomic) UIViewController *currentViewController;
#end
I am hoping that I am just missing something obvious in the way that I am loading the UITableView into the placeholderView, and something in there is causing the UITableView to go completely blank.
When you display the UITableView in a different view, you must always make sure that the view controller which "hosts" the UITableView has a strong reference to its controller. In your case, the data source for the UITableView seems to be deallocated after adding the UITableView as subview.
Changing the currentViewController property from weak to strong should fix your problem.
In swift you need to declare viewcontroller object globally that would result in Strong, in case if you declare locally it results in keep disappearing the cells.
e.g.
var refineViewController : RefineViewController?
then you can access that controller using below code that would not result in disappearing cells.
func showRefineView(isFindHomeTab isFindHomeTab : Bool){
refineViewController = RefineViewController(nibName: String(BaseGroupedTableVC),bundle : nil)
refineViewController!.refineSearchDelegate = self
refineViewController!.view.frame = CGRectMake(0, -490, self.view.frame.size.width, self.view.frame.size.height)
UIView.animateWithDuration(0.3, delay: 0.0, options: .CurveEaseOut, animations:
{
self.refineViewController!.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)
self.refineViewController!.isFindHomeTab = isFindHomeTab
}, completion: nil)
self.view.addSubview(refineViewController!.view)
}
I experienced the exact same problem. The issue was that I was using a custom datasource class (called tableVCDataSource), and was setting the tableView's dataSource incorrectly in the ViewController class. I was doing:
override func viewDidLoad() {
mainTableView.dataSource = TableVCDataSource()
}
when I should have been doing:
fileprivate var tableVCDataSource: TableVCDataSource?
override func viewDidLoad() {
tableVCDataSource = TableVCDataSource()
mainTableView.dataSource = tableVCDataSource
}
This solved my issue.

Where to put UITableViewCell logic?

For a while now I've had this dilemma on my mind. A cell in UITableView is essentially a view, thus the class for UITableViewCell should take care of view related things (i.e. presentation methods, layout and so on.) and have no business logic inside of it (usually taken care of the controller). But since we don't have a controller for each cell and only a controller for the whole table, I have trouble figuring out where to put my cell-wise logic. Putting it in the cell itself breaks MVC, but putting it in the table controller makes it hard to determine what cell the method is being called from (I prefer writing subclasses for my senders if the view is action based so I can add properties to help me determine what view this is).
For instance I have a cell, that cell has a UIButton inside of it, when the button is pushed a UIPopover appears. Now where do I put the popover presentation code (The presentation appears from one specific cell, therefore I must know which cell it's being called from.)
I'd like to know what other people do in this case and what are their best practices.
If you put the presentation of the popover inside the cell, then it's the best option. Why ?, because this is not logic, this is view related things and because the button who makes this action is inside your cell, then the code should be inside your cell (or you can send message(delegate) to your viewController to show that).
Then what is the logic ? The logic is for example: calculating, date operations, sending things to server. All these should be inside another object that we can call it module or manager.
The controller can exchange messages between all these objects (view - model), but the view and the module should be separated from each other.
Update:
You may want to take a look at Single Responsibility principle
Normally, it's to your View Controller to handle the "filling" logic for your cells. Cells are recipient that you fill each time.
It is even said in prepareForReuse: of UITableViewCell :
The table view's delegate in tableView:cellForRowAtIndexPath: should always reset all content when reusing a cell.
So indeed, your cells shouldn't hold any logic other than displaying.
If you need logic like button in your cell, you should set a delegate (you create one protocol) to your subclass of UITableViewCell and then hold in your UIViewController the cell logic.
If you cell is unique, I recommend you to define your cell as a static cell (no reuse identifier). And make a strong link to it.
You could subclass UITableView and UITableViewCell. Then, add delegate methods for the button. e.g. tableView:buttonWasPressedForCell: & buttonWasPressedForCell:. The tableView would conform to the cell's delegate and receive the message buttonWasPressedForCell:. Then, the tableView would send the message tableView:buttonWasPressedForCell: to it's delegate, in this case, your controller. This way you know which UITableView and which UITableViewCell the message was sent from.
Example:
ABCTableView.h
#protocol ABCTableViewDelegate <NSObject, UITableViewDelegate>
// You may not need this delegate method in a different UIViewController.
// So, lets set it to optional.
#optional
// Instead of passing the cell you could pass the index path.
- (void)tableView:(ABCTableView *)tableView buttonWasPressedForCell:(ABCTableViewCell *)cell;
#end
#interface ABCTableView : UITableView
// Declare the delegate as an IBOutlet to enable use with IB.
#property (weak, nonatomic) IBOutlet id<ABCTableViewDelegate> delegate;
#end
ABCTableView.m
#implementation ABCTableView
#dynamic delegate;
- (void)buttonWasPressedForCell:(ABCTableViewCell *)cell
{
// Check if the delegate responds to the selector since
// the method is optional.
if ([self.delegate respondsToSelector:#selector(tableView:buttonWasPressedForCell:)])
{
[self.delegate tableView:self buttonWasPressedForCell:cell];
}
}
#end
ABCTableViewCell.h
#protocol ABCTableViewCellDelegate;
#interface ABCTableViewCell : UITableViewCell
// Declare the delegate as an IBOutlet to enable use with IB.
#property (weak, nonatomic) IBOutlet id<ABCTableViewCellDelegate> delegate;
#end
#protocol ABCTableViewCellDelegate <NSObject>
// You may not need this delegate method in a different custom UITableView.
// So, lets set it to optional.
#optional
- (void)buttonWasPressedForCell:(ABCTableViewCell *)cell;
#end
ABCTableViewCell.m
#implementation ABCTableViewCell
- (IBAction)action:(id)sender
{
// Check if the delegate responds to the selector since
// the method is optional.
if ([self.delegate respondsToSelector:#selector(buttonWasPressedForCell:)])
{
[self.delegate buttonWasPressedForCell:self];
}
}
#end
Note:
When you dequeue the cell in tableView:cellForRowAtIndexPath: or add the cell using Interface Builder be sure to set the cell's delegate to the tableView.
E.g.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
ABCTableViewCell *cell = (ABCTableViewCell *)[tableView dequeueReusableCellWithIdentifier:#"Cell"];
cell.delegate = tableView;
return cell;
}
Usually for tasks like this I assign to cell my viewController as delegate (and define some protocol for it). Also, i keep weak reference to object from which I populate my cell, so on button's action I will forward to delegate (viewController) method like this:
- (void)actionOnCell:(UITableViewCell *)cell fromView:(UIView *)sender withItem:(id)sourceItem;
so in this way, I know where from show my popover, and what information (appropriate to sourceItem) show in it.
EDIT Also, if there multiple controls on cell to avoid duplication of pretty similar methods you can just add one parameter to function mentioned above, and define enum of all possible actions
Create an action handler and a data source for the cell. Have your data source conform to the data source protocol (View Model). Then there is no need for the cell to even know about the data model.
In the interface: TableViewCell
#property (nonatomic, weak) id <SomeTableViewCellActionHandler> actionHandler;
#protocol SomeTableViewCellActionHandler <NSObject>
- (void)cell:(SomeTableViewCell *)cell didReceiveStartButtonAction:(UIButton *)button;
- (void)cell:(SomeTableViewCell *)cell didReceivePauseButtonAction:(UIButton *)button;
- (void)cell:(SomeTableViewCell *)cell didReceiveClearButtonAction:(UIButton *)button;
#end
Implementation
- (void)prepareActionsForControls
{
[self.startButton addTarget:self action:#selector(handleStartButtonAction:) forControlEvents:UIControlEventTouchUpInside];
[self.pauseButton addTarget:self action:#selector(handlePauseButtonAction:) forControlEvents:UIControlEventTouchUpInside];
[self.clearButton addTarget:self action:#selector(handleClearButtonAction:) forControlEvents:UIControlEventTouchUpInside];
}
- (void)handleStartButtonAction:(id)sender
{
[self.actionHandler cell:self didReceiveStartButtonAction:sender];
}
- (void)handlePauseButtonAction:(id)sender
{
[self.actionHandler cell:self didReceivePauseButtonAction:sender];
}
- (void)handleClearButtonAction:(id)sender
{
[self.actionHandler cell:self didReceiveClearButtonAction:sender];
}
When you create your cell in the View Controller
create an action handler that conforms to the MyTableViewCellActionHandler protocol, pass the action handler the View Controller if it needs to do presentation.
cell.actionHandler = self.tableViewCellActionHandler;
You may also provide a datasource for your cell and pass in a View Model. (MVVM) This will allow you to keep only presentation code in the cell and keep all of your business logic where it belongs. Separation of concerns.

is it possible to segue from a UITableViewCell on a UIView to another view

Xcode 4.6.1 iOS 6 using storyboards
My problem is this
I have a UITableView with dynamic prototype cells on a UIView in a UIViewController (that is itself embedded in a navigation controller) and I want to segue from one specific cell to another view
(Before anyone suggests I should just be using a UITableViewController , I do have other things on the UIView, so i'm set up this way for a reason.)
Now i'm not sure how to go about creating the segue
If I drag from the prototype UITableViewCell to create a segue , all the generated cells automatically call the the segue - when i need only one to do so. This is normal behaviour and I would get around this if i was using a UITableViewController by creating the segue by dragging from UITableViewController and calling [self performSegueWithIdentifier:.... From my didSelectRowAtIndexPathMethod so only the specific cell I want to perform this segue triggers it.
I don't have a UITableViewController in this case - just my UITableView on a UIView that is part of a UIViewController subclass
I've been playing around and I have just discovered that i cannot drag from the UITableView - doesn't let you do that, so that was a deadend.
My only choice that seemed left to me was to drag from the UIViewController
So i tried that and of course XCode throws up an error on the perform segue line telling me i have ... No visible interface for 'LocationTV' declares the selector performSegueWithIdentifier. LocationTv being my tableview subclass.
What is the correct way to attempt to call the new view in this situation
Thank
Simon
First of all segues can be use only between UIViewControllers. So in case you want to perform a segue between two views that are on the same view controller, that's impossible.
But if you want to perform a segue between two view controllers and the segue should be trigger by an action from one view (inside first view controller) well that's possible.
So in your case, if I understand the question, you want to perform a segue when the first cell of a UITableView that's inside of a custom UIView is tapped. The easiest approach would be to create a delegate on your custom UIView that will be implemented by your UIViewController that contains the custom UIView when the delegate method is called you should perform the segue, here is a short example:
YourCustomView.h
#protocol YourCustomViewDelegate <NSObject>
-(void)pleasePerformSegueRightNow;
#end
#interface YourCustomView : UIView {
UITableView *theTableView; //Maybe this is a IBOutlet
}
#property(weak, nonatomic) id<YourCustomViewDelegate>delegate;
YourCustomview.m
#implementation YourCustomview
# synthesise delegate;
//make sure that your table view delegate/data source are set properly
//other methods here maybe
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if(indexPath.row == 0) { //or any other row if you want
if([self.delegate respondsToSelector:#selector(pleasePerformSegueRightNow)]) {
[self.delegate pleasePerformSegueRightNow];
}
}
}
YourTableViewController.h
#interface YourTableViewController : UIViewController <YourCustomViewDelegate> {
//instance variables, outlets and other stuff here
}
YourTableViewController.m
#implementation YourTableViewController
-(void)viewDidLoad {
[super viewDidLoad];
YourCustomView *customView = alloc init....
customView.delegate = self;
}
-(void)pleasePerformSegue {
[self performSegueWithIdentifier:#"YourSegueIdentifier"];
}
You can create any methods to your delegate or you can customise the behaviour, this is just a simple example of how you can do it.
My Solution
I ended up using a delegation pattern
I made a segue dragging from the my UIViewController - specifically dragging from the viewController icon (the orange circle with a white square in it - from the name bar thats under the view in the storyboard - although you could also drag from the sidebar ) to the view that i wanted to segue to.
I needed to trigger this segue from a table view cell on a table view.
TableView Bit
So i declared a protocol in my tableview header file - which is called LocationTV.h - as follows
#protocol LocationTVSegueProtocol <NSObject>
-(void) makeItSegue:(id)sender;
#end
Below that I declare a property to hold my delegate
#property (nonatomic, strong) id<LocationTVSegueProtocol> makeSegueDelegate;
To actually trigger the segue i called the makeItSegueMethod on my makeSequeDelegate in my didSelectRowAtIndexPath method
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
switch (indexPath.section) {
DLog(#"selected row %d",indexPath.row);
case dLocation:
{
if(indexPath.row == 2){
[_makeSegueDelegate makeItSegue:self];
} else if (indexPath.row == 7){
UIViewController Bit
and set up my UIViewController (named MultiTableHoldingVC) as implementing that protocol
#interface MultiTableHoldingView : UIViewController
<EnviroTVProtocol,LocationTVSegueProtocol> {
}
Below that i declared the protocol method in the list of my classes methods (although i'm not sure that is necessary as the compiler should know about the method as the decalration of implementing a protocol is essentially a promise to implement this method)
-(void) makeItSegue:(id)sender;
And then over in the implementation file of my UIViewController i wrote the method which essentially just calls preformSegueWithIdentifier
-(void) makeItSegue:(id)sender{
[self performSegueWithIdentifier:#"ChooseCountryNow"
sender:sender];
}
And to link it all together,as in the header file I had declared my instance of the tableView as follows
#property (strong, nonatomic) IBOutlet LocationTV *dsLocationTV;
I had to set that tables views delegate property to be self - which I did in my UIViewControllers -(void)ViewDidLoad method
_dsLocationTV.makeSegueDelegate = self;
It all seems a bit of a kludge calling a method to call a method and allprog suggestion is simpler (I cant for the life of me work out why it threw up errors for me) but this works just fine . Thanks to both allprog and danypata for their suggestions.
Hope this is helpful to someone out there
performSegueWithIdentifier: is a method of the UIViewController class. You cannot call it on a UITableView instance. Make your view controller implement the UITableViewDelegate protocol and set it as the delegate for the UITableView.
Another option is that you don't use segues. In the same delegate method do:
OtherViewController ov = [[OtherViewController alloc] init<<some initializer>>];
// Or in case of storyboard:
OtherViewController ov = [self.storyboard instantiateViewControllerWithIdentifier:#"ovidentifier"];
// push view controller
[self.navigationController pushViewController:ov animated:YES];
If the delegate object is different from the view controller, then the easiest solution is to add a weak property to the delegate's class that keeps a reference to the viewController, like this:
#property (weak) UIViewController *viewController;
and set it up in the viewDidLoad of the viewController
- (void) viewDidLoad {
self.tableView1.viewController = self;
}
Make sure that the tableView1 property is declared like this:
#property (IBACTION) (weak) SpecialTableView *tableView1;
Sometimes using the storyboard is more painful than writing the code yourself.

Resources