When I use replace detailView segue app crashes.
I'm replacing a bunch of view controllers, (1st is navigation controller, then tabBar controller with view controllers). tabBar Controller is a delegate of splitViewController.
Error message is:
-[TabBarController splitViewController:shouldHideViewController:inOrientation:]:
message sent to deallocated instance 0x9b7d180
Upd.: TabBarController code
// TabBarController.m
#import "TabBarController.h"
#implementation TabBarController
#synthesize masterPopoverController = _masterPopoverController;
#pragma mark - View lifecycle
- (void)awakeFromNib // always try to be the split view's delegate
{
[super awakeFromNib];
self.splitViewController.delegate = self;
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
[super viewDidLoad];
self.delegate = self;
}
- (void)viewDidUnload
{
[super viewDidUnload];
self.splitViewController.delegate = nil;
self.delegate = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
} else {
return YES;
}
}
#pragma mark - Split view
- (void)splitViewController:(UISplitViewController *)splitController willHideViewController:(UIViewController *)viewController withBarButtonItem:(UIBarButtonItem *)barButtonItem forPopoverController:(UIPopoverController *)popoverController
{
// barButtonItem.title = NSLocalizedString(#"Master", #"Master");
// [self.navigationItem setLeftBarButtonItem:barButtonItem animated:YES];
// self.masterPopoverController = popoverController;
}
- (void)splitViewController:(UISplitViewController *)splitController willShowViewController:(UIViewController *)viewController invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem
{
// Called when the view is shown again in the split view, invalidating the button and popover controller.
// [self.navigationItem setLeftBarButtonItem:nil animated:YES];
// self.masterPopoverController = nil;
}
- (BOOL)splitViewController:(UISplitViewController *)svc shouldHideViewController:(UIViewController *)vc inOrientation:(UIInterfaceOrientation)orientation
{
return NO;
}
#end
The problem was that I assigned delegate of UISplitViewController to detailView.
Restarting detailView cause memory problems.
After I made AppDelegate also the delegate of UISplitViewController problem was solved.
Related
I tried setting shouldAutorotate to false
supportedInterfaceOrientations to UIInterfaceOrientationLandscapeRight
-(BOOL)shouldAutorotate{
return NO;
}
-(NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationLandscapeRight;
}
supportedInterfaceOrientations is enough, just remove shouldAutorotate.
or you can do so.
NavigationController.m
#interface NavigationController : UINavigationController
#end
#implementation NavigationController
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
return [self.topViewController supportedInterfaceOrientations];
}
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
[super pushViewController:viewController animated:animated];
[self refreshOrientation];
}
- (UIViewController *)popViewControllerAnimated:(BOOL)animated {
id vc = [super popViewControllerAnimated:animated];
[self refreshOrientation];
return vc;
}
- (NSArray<UIViewController *> *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated {
id vcs = [super popToViewController:viewController animated:animated];
[self refreshOrientation];
return vcs;
}
- (NSArray<UIViewController *> *)popToRootViewControllerAnimated:(BOOL)animated {
id vcs = [super popToRootViewControllerAnimated:animated];
[self refreshOrientation];
return vcs;
}
- (void)refreshOrientation {
UIViewController *vc = [UIViewController new];
[UIViewController attemptRotationToDeviceOrientation];
[self presentViewController:vc animated:NO completion:nil];
[vc dismissViewControllerAnimated:NO completion:nil];
}
#end
in ViewController implement this method
-(UIInterfaceOrientationMask)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskLandscapeLeft;
}
My Environment is Xcode 6.3, target is iOS8.3 for iPad.
I'm learning the Master-Detail view by using Xcode's template. Some strange problem appears when I try to set a label's text in the detail view:
If I put the statement which changes the label's text in P1 position, it works.
But if I put the statement in P2 position, it doesn't work.
Under both circumstances, the detailDescriptionLabel.text was changed, but only the P1 statement actually update the screen.(I have checked that function configureView() was called both times)
Can anybody helps me? Thanks a lot.
Below are my code snippets:
MasterController.m:
#import "MasterViewController.h"
#import "DetailViewController.h"
#interface MasterViewController ()
#property (copy, nonatomic) NSMutableArray *objects;
#end
#implementation MasterViewController
- (void)awakeFromNib {
[super awakeFromNib];
self.clearsSelectionOnViewWillAppear = NO;
self.preferredContentSize = CGSizeMake(320.0, 600.0);
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSString *path = [[NSBundle mainBundle] pathForResource:#"PresidentList" ofType:#"plist"];
NSDictionary *presidentInfo = [NSDictionary dictionaryWithContentsOfFile:path];
self.objects = [NSMutableArray arrayWithArray:[presidentInfo objectForKey:#"presidents"]];
self.detailViewController = (DetailViewController *)[[self.splitViewController.viewControllers lastObject] topViewController];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Segues
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"showDetail"]) {
DetailViewController *controller = (DetailViewController *)[[segue destinationViewController] topViewController];
controller.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem;
controller.navigationItem.leftItemsSupplementBackButton = YES;
//P1
//controller.detailItem = (self.objects[indexPath.row])[#"url"];
}
}
#pragma mark - Table View
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.objects.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
cell.textLabel.text = (self.objects[indexPath.row])[#"name"];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
//P2
//self.detailViewController.detailItem = (self.objects[indexPath.row])[#"url"];
}
#end
DetailController.m:
#import "DetailViewController.h"
#interface DetailViewController ()
#property (strong, nonatomic) UIPopoverController *masterPopoverController;
#end
#implementation DetailViewController
#pragma mark - Managing the detail item
- (void)setDetailItem:(id)newDetailItem {
if (_detailItem != newDetailItem) {
_detailItem = newDetailItem;
// Update the view.
[self configureView];
}
if (self.masterPopoverController != nil) {
[self.masterPopoverController dismissPopoverAnimated:YES];
}
}
- (void)configureView {
// Update the user interface for the detail item.
if (self.detailItem) {
self.detailDescriptionLabel.text = self.detailItem;
}
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self configureView];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Split view
- (void)splitViewController:(UISplitViewController *)svc willHideViewController:(UIViewController *)aViewController withBarButtonItem:(UIBarButtonItem *)barButtonItem forPopoverController:(UIPopoverController *)pc {
barButtonItem.title = NSLocalizedString(#"Master", #"Master");
[self.navigationItem setLeftBarButtonItem:barButtonItem animated:YES];
self.masterPopoverController = pc;
}
- (void)splitViewController:(UISplitViewController *)svc willShowViewController:(UIViewController *)aViewController invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem {
[self.navigationItem setLeftBarButtonItem:nil animated:YES];
self.masterPopoverController = nil;
}
#end
I guess you are using segues and that's the point of using the dedicated function (prepareForSegue) designated appositely to initialize values AFTER the view destination view has been anyway created.
Unless you instantiate and show the view by yourself in didSelectRowAtIndexPath there is no point in setting something to such a viewcontroller.
I'm going to guess that self.detailViewController is nil. Hence P2 will not work.
Difficult to say without seeing all the code but in prepareForSegue, you might want to assign it there.
How can I dismiss/pop a UIPageViewController after the last view controller is swiped?
Basically want to make a tutorial style paging view with images, and to dismiss after the user swipes to the "next" page from the last.
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController {
NSUInteger index = [(EmailTutorialViewController *)viewController index];
index++;
if (index == 5) {
[self.navigationController popViewControllerAnimated:YES]; // this doesn't do anything
return nil;
}
return [self viewControllerAtIndex:index];
}
Here's simple solution I've used:
In
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController;
return empty controller for index == 5 and add this UIPageViewControllerDelegate method:
- (void)pageViewController:(UIPageViewController *)pageViewController
willTransitionToViewControllers:(NSArray *)pendingViewControllers
{
EmailTutorialViewController *viewController =
[pendingViewControllers objectAtIndex:0];
if ([viewController index] == 5)
{
[self.navigationController popViewControllerAnimated:YES];
}
}
Within your UIPageViewController or viewController conforming to the UIPageViewControllerDelegate protocol:
// UIPageViewController.h
#interface UIPageViewController
#property (nonatomic, assign) NSInteger pageIndex;
#end
// UIPageViewController.m
#implementation UIPageViewController
/* ... */
- (void)viewDidLoad
{
[super viewDidLoad];
// Start with animation from the presenting view/item.
UIViewController *singlePageVC = [UIViewController viewControllerWithPageIndex:self.pageIndex];
singlePageVC.view.alpha = 0.0f;
if (singlePageVC != nil) {
self.dataSource = self;
self.delegate = self;
// Add singlePageVC to the page view controller with the initial pageIndex.
[self setViewControllers:#[ singlePageVC ]
direction:UIPageViewControllerNavigationDirectionForward
animated:NO
completion:nil];
}
}
#pragma mark - UIPageViewControllerDelegate
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
viewControllerBeforeViewController:(UIViewController *)viewController
{
NSInteger index = singlePageVC.pageIndex;
// This will add a page before the current view controller.
// Even if the index is 0, a new (dismissing) view controller will be added here.
return [UIViewController viewControllerWithPageIndex:index - 1];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
viewControllerAfterViewController:(UIViewController *)viewController
{
NSInteger index = singlePageVC.pageIndex;
// This will add a page after the current view controller.
// Even if the index is at your array bounds (i.e., 5), a new (dismissing) view controller will be added here.
return [UIViewController viewControllerWithPageIndex:index + 1];
}
/* ... */
#end
// UIViewController+PageIndex.h
extern NSString * const UIViewControllerShouldDismissFromPageViewControllerNotification;
#interface UIViewController (PageIndex)
#property (nonatomic, assign) NSInteger pageIndex;
- (instancetype)initWithPageIndex:(NSInteger)pageIndex;
+ (instancetype)viewControllerWithPageIndex:(NSInteger)pageIndex;
#end
// UIViewController+PageIndex.m
NSString * const UIViewControllerShouldDismissFromPageViewControllerNotification = #"UIViewControllerShouldDismissFromPageViewControllerNotification";
#implementation UIViewController (PageIndex)
// Initialize with the current item's index.
- (instancetype)initWithPageIndex:(NSInteger)pageIndex
{
self = [super init];
if (self) {
_pageIndex = pageIndex;
}
return self;
}
+ (instancetype)viewControllerWithPageIndex:(NSInteger)pageIndex
{
return [[self alloc] initWithPageIndex:pageIndex];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// Check for pageIndex out of bounds of your array.
// This will be either less than 0 or greater or equal to your array count.
if (self.pageIndex < 0 || self.pageIndex >= array.count) { // Replace with your global or passed array here.
// Post dismiss notification here.
[[NSNotificationCenter defaultCenter]
postNotificationName:UIViewControllerShouldDismissFromPageViewControllerNotification
object:nil];
return;
}
}
#end
// View controller than manages your UIPageViewController.
#implementation YourViewController
/* ... */
- (void)viewDidLoad
{
[[NSNotificationCenter defaultCenter]
addObserver:self selector:#selector(dismissPageViewController:)
name:UIViewControllerShouldDismissFromPageViewControllerNotification
object:nil];
}
- (void)dismissPageViewController:(NSNotification *)notification
{
// Dismiss your page view controllers here.
[self.pageViewController dismissViewController];
self.pageViewController = nil;
// Or remove the page view controllers from its parent view controller,
[self.pageViewController willMoveToParentViewController:nil];
[self.pageViewController removeFromParentViewController];
[self.pageViewController didMoveToParentViewController:nil];
// Or its view from its super view.
[self.pageViewController.view removeFromSuperview];
self.pageViewController = nil;
}
/* ... */
#end
So, I think that when I click outside of a popover, the method popoverControllerDidDismissPopover should be called. I know this isn't called when dismissPopoverAnimated is called.
I have a simple project that I have setup that shows popoverControllerDidDismissPopover just isn't called:
#import "ViewController.h"
#import "PopoverViewController.h"
#interface ViewController ()
{
PopoverViewController *controller;
UIPopoverController *popoverController;
}
#end
#implementation ViewController
#synthesize button;
- (IBAction)showPopover:(UIButton *)sender
{
if ([popoverController isPopoverVisible]) {
[popoverController dismissPopoverAnimated:YES];
} else {
CGRect popRect = CGRectMake(self.button.frame.origin.x,
self.button.frame.origin.y,
self.button.frame.size.width,
self.button.frame.size.height);
[popoverController presentPopoverFromRect:popRect
inView:self.view
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
controller = [[PopoverViewController alloc] initWithNibName:#"PopoverViewController" bundle:nil];
popoverController = [[UIPopoverController alloc] initWithContentViewController:controller];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController {
NSLog(#"Why am I never called!!!!");
}
- (BOOL)popoverControllerShouldDismissPopover:(UIPopoverController *)popoverController
{
return true;
}
#end
Please tell me where I'm going wrong or how I can detect when a popover is dismissed.
The whole project is here:
https://rapidshare.com/files/3182903825/PopoverDemo.zip
You never set the delegate for your popoverController to self.
_popoverController.delegate = self;
You didn't set the delegate of your popoverController. Add the following code to the end of the viewDidLoad method:
popoverController.delegate = self;
Good day to you guys
I have an application that has a UITabBarController for tabbed-navigation... The view-controllers are mapped to their respective TabItems via a URL, just the same as that of Three20's TTNavigationSample App.
My problem is that inside a view controller of mine, i have a button that calls to another view controller which is also attached to a TabItem. When i trigger the button, the application throws an error. How can I resolve this?
In my TabBarController, i have this inside the viewDidLoad method:
-(void)viewDidLoad {
[self setTabURLs: [NSArrayWithObjects:
#"tt://bulletinBoard",
#"tt://contacts",
nil
]];
}
Sample .m file
#import "HabBarController.h"
#implementation TabBarController
- (void)viewDidLoad {
//these are variables like "tt/feed"
[self setTabURLs:[NSArray arrayWithObjects:
kAppFeedURLPath,
kAppHotURLPath,
kAppPostPhotoURLPath,
kAppGeneralActivityURLPath,
nil]];
}
- (UIViewController*)rootControllerForController:
(UIViewController*)controller {
if ([controller canContainControllers]) {
return controller;
} else {
UINavigationController* navController = [[[UINavigationController
alloc] init] autorelease];
[navController pushViewController:controller animated:NO];
return navController;
}
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[self.tabBarController.navigationController setNavigationBarHidden:YES animated:NO];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)viewDidUnload {
[super viewDidUnload];
}
- (void)dealloc {
[super dealloc];
}
#end