Due to the neeeds of the aplication I need to call a method from a cell class of a collection view. The method is in a detail view controller which implementes the collection view .
If I call the method completely from viewDidLoad of the detail view controller at aplication start everything goes well and the button is added in the navigation bar as intended, but when I call the same method from the cell class nothing happens. Do I forget something?
Here is the code
collectionViewCell.m
- (void) addButtonToNavigationBar {
DetailViewController *dvc = [[DetailViewController alloc]init]
[dvc implementButton];
}
DetailViewController.h
- (void) implementButton;
DetailViewController.m
- (void) implementButton {
addButton = [[UIBarButtonItem alloc] initWithTitle:#"Done"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(editTable)];
[self.navigationItem.rightBarButtonItem setStyle:UIBarButtonItemStyleBordered];
[self.navigationItem setRightBarButtonItem:addButton animated:YES];
Thank you for any hint.
When you write DetailViewController *dvc = [[DetailViewController alloc]init]; you are creating a new controller. It's not the one that already exists.
For your situation, you might consider having the controller listen for a NSNotification from the cell and call implementButton when it receives it.
Related
I try to implement adaptive UI in my app. By making UISplitViewController as the rootview controller, I can run the iPhone's code in iPad too.
I red Apple's documentation about UISplitViewController and some samples. All are using storyboards and the sample codes are available in swift only. I can not find a working version of code. So I started the code myself.
See my splitview controller class (BaseSplitViewController)
BaseSplitViewController.h:
#import <UIKit/UIKit.h>
#interface BaseSplitViewController : UISplitViewController <UISplitViewControllerDelegate>
#end
BaseSplitViewController.m:
#import "BaseSplitViewController.h"
#import "TabBarViewController.h"
#interface BaseSplitViewController ()
#property(nonatomic, strong) TabBarViewController *primaryTabBarVC;
#property(nonatomic, strong) UINavigationController *primaryNavigationController;
#property(nonatomic, strong) UINavigationController *secondaryNavigationController;
#end
#implementation BaseSplitViewController
- (instancetype)init
{
self = [super init];
if (self)
{
[self setViewControllers:#[self.primaryNavigationController, self.secondaryNavigationController]];
self.delegate = self;
self.preferredDisplayMode = UISplitViewControllerDisplayModeAutomatic;
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(cellTapped:) name:#"cellTapped" object:nil];
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self assignPrimaryViewController];
}
- (void)assignPrimaryViewController
{
// Need to assign tab bar controller as primary view controller here
}
- (void)assignSecondaryViewController:(UIViewController *)vc
{
// Need to update the secondary controller each time the primary controller was tapped
}
- (UINavigationController *)primaryNavigationController
{
if (!_primaryNavigationController)
{
_primaryNavigationController = [[UINavigationController alloc] init];
}
return _primaryNavigationController;
}
- (UINavigationController *)secondaryNavigationController
{
if (!_secondaryNavigationController)
{
_secondaryNavigationController = [[UINavigationController alloc] init];
}
return _secondaryNavigationController;
}
- (UITabBarController *)primaryTabBarVC
{
if (!_primaryTabBarVC)
{
_primaryTabBarVC = [[TabBarViewController alloc] init];
}
return _primaryTabBarVC;
}
#end
Some points:
The above class "BaseSplitViewController" is the rootview controller of my app.
That is, self.window.rootViewController = [[BaseSplitViewController alloc] init];
From Apple's Documentation,
"When designing your split view interface, it is best to install
primary and secondary view controllers that do not change. A common
technique is to install navigation controllers in both positions and
then push and pop new content as needed. Having these types of anchor
view controllers makes it easier to focus on your content and let the
split view controller apply its default behavior to the overall
interface."
So, I created two navigation controllers (primary/secondary) and set them as split view controllers's primary & secondary views. setViewControllers: can be used for this.
My primary view here is, tab bar view. So, inside the assignPrimaryViewController: method, I should assign my TabBarViewController as split view controller's primary view.
Here, I found two ways.
1. [self.primaryNavigationController showViewController:self.primaryTabBarVC sender:nil];
2. [self.primaryNavigationController pushViewController:self.primaryTabBarVC animated:YES];
Here, I tried with [self showViewController:self.primaryTabBarVC sender:nil]; but my tab bar view was never shown. From my understanding, here "self" means the UISplitViewController. Calling showViewController: here makes the confusion to choose the navigation controller. Because we have two navigation controllers. So we need to clearly tell that navigation controller which needs to hold the primary controller.
Primary view controller part is over. Now the real problem starts. Consider my primary view controller is the tab bar which have tableview's in it. If I tap on the cell, I need to update the secondary view's content. This is the case in Regular mode. In compact mode, I expect when the user taps on the cell, it should push the detail view (secondary view) with back button.
I expect to put the below code within assignSecondaryViewController: vc: method
[self.secondaryNavigationController pushViewController:vc animated:NO];
[self.primaryNavigationController showDetailViewController:self.secondaryNavigationController sender:nil];
But it does not works.
Questions:
What should be placed inside assignPrimaryViewController & assignSecondaryViewController: methods to get my expected result?
And I really, yes really don't know how to implement UISplitViewController's following delegate methods.
primaryViewControllerForCollapsingSplitViewController:
splitViewController:collapseSecondaryViewController:ontoPrimaryViewController:
primaryViewControllerForExpandingSplitViewController:
splitViewController:separateSecondaryViewControllerFromPrimaryViewController:
Would be really helpful, if someone explains this new UISplitViewController's behavior.
Thanks
when we touch the tabbaritem of the tabbarcontroller the delegate methods are called:
-(BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController;
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController;
but when try to do the same thing programmatically, i.e.
[self.tabbarController setSelectedIndex:selectedIndexNo];
or
[self.tabBarController setSelectedViewController:[self.tabBarController.viewControllers objectAtIndex:0]];
the delegate methods are not called. What is the reason for that?
override UITabBarController setSelectedIndex:
-(void)setSelectedIndex:(NSUInteger)selectedIndex
{
//must call super function.
[super setSelectedIndex:selectedIndex];
[self myMethod];
}
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{
[self myMethod];
}
When you are setting them yourself via code, than you are aware that this is the time when the delegate method will be called. so whatever you wish to do you can do it at the time of setting the index programmatically. Say you want to call a method aMethod on tabbardelegate being called. you can call the method as soon as you set the index.
[self.tabbarController setSelectedIndex:selectedIndexNo];
[self aMethod];
I am making a splitview application for ipad and I need to display a different view controller for login purposes.
I call this in the didFinishLaunchingWithOptions function in Appdelegate:
LoginViewController *login = [[LoginViewController alloc] init];
[info setModalTransitionStyle: UIModalTransitionStyleCrossDissolve];
[self presentViewController:login animated:YES completion: nil];
but I get the error "No visible #interface for AppDelegate declares the selector presentViewController" on the third line.
The view controller I want to display is set to the LoginViewController class.
I have Imported all classes.
I am pretty new to programming and would really appreciate any help!
Thanks!!
What the error message says is that the class AppDelegate does not contain a method called presentViewController. Indeed, that method belongs to UIViewController class.
What you should do depends on how you created your project, whether it uses a navigation controller, a tab bar controller, or a simple view controller.
From your comment, I understand you used the Window-based template (or Empty application) to create your project. In this case, in your application:didFinishLaunching: you should have something like this:
self.login = [[LoginViewController alloc] init];
[self.window addSubview:self.login.view];
and also add to your AppDelegate.h the following declaration:
#property (nonatomic, strong) LoginViewController* login;
If this seems not to apply to your case, please, post your definition of application:didFinishLaunching:
Hy all.
Since i am using IOS 5 , therefore i am using storyboard.
In the older versions, i could easily write initWithNibName:#"Details", and it worked like a charm.
Now in storyboard, and since i am not using any XIB file, i need to do the same thing.
Here's a snippet of my code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
//Get the selected country
NSString *selectedAuthors = [theauthors objectAtIndex:indexPath.row];
//Initialize the detail view controller and display it.
Details *dvController = [[Details alloc] initWithNibName:#"Details" bundle:nil];
dvController.selectedAuthors = selectedAuthors;
[self.navigationController pushViewController:dvController animated:YES];
[dvController release];
dvController = nil;
}
My new Snippet :
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
//Get the selected country
NSString *selectedAuthors = [theauthors objectAtIndex:indexPath.row];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard.storyboard" bundle:nil];
Details *dvController = [storyboard instantiateViewControllerWithIdentifier:#"Details"]; //Or whatever identifier you have defined in your storyboard
//Initialize the detail view controller and display it.
//Details *dvController = [[Details alloc] init/*WithNibName:#"Details" bundle:nil*/];
dvController.selectedAuthors = selectedAuthors;
[self.navigationController pushViewController:dvController animated:YES];
[dvController release];
dvController = nil;
}
Application Log :
2012-07-17 16:30:15.760 AuthorsApp[6534:f803] WARNING: Using legacy cell layout due to delegate implementation of tableView:accessoryTypeForRowWithIndexPath: in <AuthorVC: 0x6857ba0>. Please remove your implementation of this method and set the cell properties accessoryType and/or editingAccessoryType to move to the new cell layout behavior. This method will no longer be called in a future release.
2012-07-17 16:30:16.167 AuthorsApp[6534:f803] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Storyboard (<UIStoryboard: 0x6867750>) doesn't contain a view controller with identifier 'Details''
*** First throw call stack:
(0x1595022 0x1726cd6 0x500fef 0x3151 0x1675c5 0x1677fa 0x9fc85d 0x1569936 0x15693d7 0x14cc790 0x14cbd84 0x14cbc9b 0x147e7d8 0x147e88a 0xd6626 0x1dc2 0x1d35)
terminate called throwing an exception(lldb)
Latest Application Log:
2012-07-17 16:35:15.352 AuthorsApp[6600:f803] WARNING: Using legacy cell layout due to delegate implementation of tableView:accessoryTypeForRowWithIndexPath: in <AuthorVC: 0x688d810>. Please remove your implementation of this method and set the cell properties accessoryType and/or editingAccessoryType to move to the new cell layout behavior. This method will no longer be called in a future release.
2012-07-17 16:35:15.912 AuthorsApp[6600:f803] Everything is ok now !
(lldb)
Final Log
Couldn't register com.test.erc.AuthorsApp with the bootstrap server. Error: unknown error code.
This generally means that another instance of this process was already running or is hung in the debugger.(lldb)
You could instantiate the controller that is located in your storyboard like this:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"myStoryboard" bundle:nil];
Details *dvController = [storyboard instantiateViewControllerWithIdentifier:#"Details"]; //Or whatever identifier you have defined in your storyboard
Another option since you're using Storyboards would be using segues for the transitions. Here is a nice example. One thing that you get for free with segues is that the destination controller gets instantiated automatically for you. The delegate method looks like this:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([[segue identifier] isEqualToString:#"Details"]){
Details *dvController = (Details *)[segue destinationViewController];
// Pass any data to destination controller
// The transition is handled by the segue and defined in the Storyboard ('push' for example)
}
}
EDIT
Here is a screenshot for easy reference:
How to handle situation when I use ARC and add view of UIViewController?
MyViewController *vc = [[MyViewController alloc] initWithNibName:#"MyViewController" bundle:nil];
[someView addSubview:vc.view]; //this retain vc.view
because addSubview retain onlu view, not controller, so controller is released. Before ARC there was a way to retain controller as long as neede, but how to prevent ARC to release View Controller?
I had similar situation solved by declaring vc as property with default strong attribute.
#define AntiARCRetain(...) void *retainedThing = (bridge_retained void *)__VA_ARGS; retainedThing = retainedThing
And then call AntiARCRetain(controller);
Why would you need a new ViewController there?
You should just add your View as Subview and handle everything with the ViewController of "someView"