iPhone/Objective-c - Gaining access to a previous ViewController from a subview? - iphone

How do I access a previous view controller while in a subview? Because I'm able to perform actions but I'm just not able to use self.[my main view controller].
This is my code, for testing purposes:
PhotoViewController.m
-(IBAction)likeButton:(UIButton *)sender
{
//this part works
NSString *num = #"2";
self.label.text = [NSString stringWithFormat:#"%# + %#",
self.label.text,
num];
//this part doesn't work
//switch over to the third view to see if it worked
self.tabBarController.selectedIndex = 0;
}
I have a UITabBarController and one of its view controllers has a UIScrollView. Inside of the UIScrollView is a PhotoViewController object.
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch
MyTabBarViewController *vc2 = [[MyTabBarViewController alloc] init];
SecondViewController *vc3 = [[SecondViewController alloc] init];
controller = [[DemoAppViewController alloc] init];
controller.view.frame = CGRectMake(0, 20, 320, 460);
controller.title = #"Intro Screen";
vc2.title = #"Explore";
vc3.title = #"Send a Pic";
UITabBarController *tbc = [[UITabBarController alloc] init];
tbc.viewControllers = [NSArray arrayWithObjects:controller, vc2, vc3, nil];
[controller release];
[vc2 release];
[vc3 release];
[self.window addSubview:tbc.view];
[self.window makeKeyAndVisible];
return YES;
}
Also, my TabBarViewController.m //not my actual UITabBarController though, wording is confusing
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:YES];
arrayCount = [array count];
scroller.delegate=self;
scroller.pagingEnabled=YES;
scroller.directionalLockEnabled=YES;
scroller.showsHorizontalScrollIndicator=NO;
scroller.showsVerticalScrollIndicator=NO;
//should have an array of photo objects and the number of objects, correct?
scrollWidth = 0;
scroller.contentSize=CGSizeMake(arrayCount*scroller.frame.size.width, scroller.frame.size.height);
for (int i = 0; i < arrayCount;i++) {
PhotoViewController *pvc = [[PhotoViewController alloc] initWithNibName:#"PhotoViewController" bundle:nil];
UIImageView *scrollImageView = [[UIImageView alloc] initWithFrame:CGRectOffset(scroller.bounds, scrollWidth, 0)];
CGRect rect = scrollImageView.frame;
pvc.view.frame = rect;
pvc.label.textColor = [UIColor whiteColor];
id individualPhoto = [array objectAtIndex:i];
NSLog(#"%#",individualPhoto);
NSArray *keys=[individualPhoto allKeys];
NSLog(#"%#",keys);
NSString *imageURL=[individualPhoto objectForKey:#"source"];
NSURL *url = [NSURL URLWithString:imageURL];
NSData *data = [NSData dataWithContentsOfURL:url];
pvc.imageView.image = [[UIImage alloc] initWithData:data];
pvc.label.text = [individualPhoto objectForKey:#"id"];
[scroller addSubview:pvc.view];
[scrollImageView release];
//[pvc release];
scrollWidth += scroller.frame.size.width;
}
if (arrayCount > 3) {
pageControl.numberOfPages=3;
} else {
pageControl.numberOfPages=arrayCount;
}
pageControl.currentPage=0;
}

If a UIView subclass needs to message a controller above itself, a common (and often recommended?) way to do this is to have the view subclass implement the delegate protocol (a weak linked instance variable pointing to the view controller that you want to use). The view controller should then set itself as the delegate of the view when that view is being initialize.

Try defining this method in your PhotoViewController:
+ (YOURTABBARCONTROLLER*)parentTabBarController:(UIResponder*)view {
id nextResponder = nil;
id v = view;
while (nextResponder = [v nextResponder]) {
NSLog(#"Found Responder: %#", nextResponder); //-- ADDED THIS
if ([nextResponder isKindOfClass:[YOURTABBARCONTROLLER class]])
return nextResponder;
v = nextResponder;
}
return nil;
}
it will traverse the responder chain and return the first controller of a given type that is found. Replace YOURTABBARCONTROLLER with your actual tab bar controller class and you should be able to have:
-(IBAction)likeButton:(UIButton *)sender
{
//this part works
NSString *num = #"2";
self.label.text = [NSString stringWithFormat:#"%# + %#",
self.label.text,
num];
[PhotoViewController parentTabBarController:self.view].selectedIndex = 0;
// self.tabBarController.selectedIndex = 0;
}
Updated
-(IBAction)likeCommentButton:(UIButton *)sender
{
//code goes here
TypeSomethingViewController *typeSomethingViewController = [[TypeSomethingViewController alloc] init];
typeSomethingViewController.delegate = self;
[self presentModalViewController:typeSomethingViewController animated:YES];
[typeSomethingViewController release];
}
-(void)typeSomethingViewController:(TypeSomethingViewController *)controller didTypeSomething:(NSString *)text
{
//NSLog(#"response: %#", controller);
NSString *commentID = self.label.text;
for(UIViewController *controller in [PhotoViewController parentTabBarController:self.parentViewController.view].viewControllers)
{
if([controller isKindOfClass:[DemoAppViewController class]])
{
DemoAppViewController *davc = (DemoAppViewController *)controller;
//[davc commentPicture:commentID :message];
[davc likePicture:commentID];
}
}
[PhotoViewController parentTabBarController:self.view].selectedIndex = 0;
[self dismissModalViewControllerAnimated:YES];
}

Try this out to switch to the first controller.
self.tabBarController.selectedViewController
= [self.tabBarController.viewControllers objectAtIndex:0];
Change the index value to switch to whichever controller you want to switch to.

The tabBarController should be a property of the app delegate.
Try accessing it with :
MyAppDelegate *appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication]
delegate];
appDelegate.tabBarController.selectedIndex = 0;
Unless you declare the same property in PhotoViewController, you won't be able to access it this way.
Try importing the app delegate header in PhotoViewController.h like so :
#import "MyAppDelegate"
then try this code above replacing tabBarController by tbc which, as the example suggests is the name given to this property.

Related

Can't get tabbar app to popToRootViewController

I have a programatic tabbar delagate with navbar with a banner view delegate. And for the life of me I can't seem to get the tabs to pop the root view on click. I know I need to use something like [self.navigationController popToRootViewControllerAnimated:NO]; But I don't know where to put it in my app delegate.
#implementation AppDelegate {
UITabBarController *_tabBarController;
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions
{
NSError *setCategoryError = nil;
CGRect bounds = [[UIScreen mainScreen] bounds];
self.window = [[UIWindow alloc] initWithFrame:bounds];
self.window.backgroundColor = [UIColor whiteColor];
NSMutableArray * viewControllers = [[NSMutableArray alloc] init];
NSString * subscriptionListFile = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:#"Subscription.plist"];
NSDictionary * subscriptionList = [[NSDictionary alloc] initWithContentsOfFile:subscriptionListFile];
NSArray * subscriptionFolders = subscriptionList[#"Folders"];
NewsListViewController * newsController = nil;
UINavigationController * newsNavigationController = nil;
BannerViewController * bannervcs = nil;
for (NSDictionary * folderDetails in subscriptionFolders) {
NSArray * newsItems = folderDetails[#"Items"];
NSString * folderTitle = folderDetails[#"FolderName"];
NSString * folderIcon = folderDetails[#"FolderIcon"];
UIImage * folderIconImage = [UIImage imageNamed:folderIcon];
newsController = [[NewsListViewController alloc] initWithNewsSourceList:newsItems];
[newsController setTitle:folderTitle];
newsNavigationController = [[UINavigationController alloc] initWithRootViewController:newsController];
[newsNavigationController setTitle:folderTitle];
bannervcs = [[BannerViewController alloc] initWithContentViewController:newsNavigationController];
[bannervcs.tabBarItem setImage:folderIconImage];
[viewControllers addObject:bannervcs];
}
_tabBarController = [[UITabBarController alloc] init];
_tabBarController.viewControllers = viewControllers;
self.window.rootViewController = _tabBarController;
[self.window makeKeyAndVisible];
return YES;
}
#end
Any idea where I add popToRootViewController? I tried at the end but it doesnt seem to be grabbing any controller...
You'll need to set something to be your UITabBarControllerDelegate. Assuming you want to try this out on your AppDelegate, add the line to your method:
_tabBarConroller.delegate = self;
And then, add this method to your AppDelegate (since it is now also considered an UITabBarControllerDelegate)
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{
viewController.navigationController popToRootViewControllerAnimated:NO];
}
This is assuming that, regardless of what state the user left the navigation stack on a tab, that tapping another tab always takes the user to the root view controller of the nav stack.
If you want navigationController in your tabBar then you have to add yourNavigationController instead of viewController.
So in your case you are not adding navigationControllers to your tabBarControllers array.
[viewControllers addObject:bannervcs];
so instead of adding bannervcs add newsNavigationController
[viewControllers addObject:newsNavigationController];
For more info just read and take sample code from UITabBarController Class Reference

Subclassed UIView not displaying UIImageViews added to it

So I have class called CSImageViews (subclass of uiview), that is essentially a row of UIImageViews enclosed in a single subclassed UIView.
I've added a custom init method like so (node/yaml contains uiimage name data):
- (id)initWithFrame:(CGRect)frame withNode:(NSDictionary *)node
{
self = [super initWithFrame:frame];
if (self) {
_node = node;
_imageViewYAML = [node objectForKey:#"items"];
_imageViews = [self getImageViewsForItems:_imageViewYAML];
}
return self;
}
And my getImageViewsforItems is like so (adds them all to subview):
-(NSArray *)getImageViewsForItems:(NSArray *)items
{
NSMutableArray *ivs = [NSMutableArray arrayWithCapacity:[items count]];
for (int i = 0; i < [items count]; i++) {
NSDictionary *item = [items objectAtIndex:i];
NSString *type = [item objectForKey:#"type"];
NSString *name = [item objectForKey:#"name"];
UIImage *image = [UIImage imageNamed:name];
UIImageView *iv = [[UIImageView alloc] init];
iv.image = image;
iv.tag = i;
[ivs addObject:iv];
[self addSubview:iv];
}
return ivs;
}
Now when I add this custom view to my main view like this nothing happens:
CSImageViews *imageViews = [[CSImageViews alloc] initWithFrame:frame withNode:node];
[view addSubview:imageViews];
But if I add this 'csimageviews' container into a new uiview first it appears:
CSImageViews *imageViews = [[CSImageViews alloc] initWithFrame:frame withNode:node];
UIView *v = [[UIView alloc] initWithFrame:frame];
[v addSubview:imageViews];
[view addSubview:v];
thoughts?
Stupid error by me. In this particular subclassed UIView I have a method that was called every time its parent view controller was shown. This method actually removed all subviews from the view... so I wasn't able to see the uiimageviews when I rendered it in the initial view... doh.

iOS - Unexpected crash when popping and pushing a view controller with a MKMapView

Hi there can anyone help me with the following problem:
I have a ViewController with a MKMapView inside of it, and when i pop this view everything is alright but when i try to push this ViewController back in my NavigationController's stack my app crashes unexpectedly.
I tried to fix this problem by enabling NSZombie and it worked fine while running from xcode, but when i tried to run it in the simulator (and on my iPhone) without using xcode and it still crashes. I also tried to make my mapview delegete nil in ViewWillDissapear, ViewDidDissapear and dealloc but i still have the same problem.
Can anyone help me with this?
This is the log output when the app crashes:
-[__NSCFType observedViewControllerChange:]: unrecognized selector sent to instance 0x79a6f50
2012-09-14 11:28:13.878***[456:12503] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFType observedViewControllerChange:]: unrecognized selector sent to instance 0x79a6f50'
* First throw call stack:
(0x19af022 0x179ecd6 0x19b0cbd 0x1915ed0 0x1915cb2 0x12c3a29 0x197a855 0x197a778 0x120819a 0x9d9c97 0xb810be 0xb813c7 0xb81436 0x931e49 0x931f34 0x6c0b54 0x1f2c509 0x18e6803 0x18e5d84 0x18e5c9b 0x30967d8 0x309688a 0x901626 0x46ad 0x2d55)
terminate called throwing an exception(lldb)
I am using arc. And here is some code:
I do a lot of things in my viewDidLoad function and i think that the problem might be here this is the code:
This the .h:
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import <CoreLocation/Corelocation.h>
#import "AddressViewController.h"
#import "Utilities.h"
#import "MarqueeLabel.h"
#import "CustomButton.h"
#interface LocationViewController : UIViewController<MKMapViewDelegate,CLLocationManagerDelegate,UIGestureRecognizerDelegate>{
CLLocationManager *locationManager;
MKPointAnnotation *centerAnnotation;
int initialState;
NSDictionary * json;
bool google;
bool isBackgroundRunning;
double x;
CLLocationCoordinate2D selectedCoordinate;
MarqueeLabel *continuousLabel;
__weak IBOutlet CustomButton *cont;
UILongPressGestureRecognizer *lgr;
UIPanGestureRecognizer *panGesture;
UIPinchGestureRecognizer *pinchGesture;
UISwipeGestureRecognizer *swipeGesture;
__weak IBOutlet UIButton *myLoc;
BOOL first;
}
#property (strong, nonatomic) IBOutlet MKMapView *myMapView;
- (IBAction)showMe:(id)sender;
#property (strong, nonatomic) MKPointAnnotation *centerAnnotation;
#end
- (void)viewDidLoad
{
[super viewDidLoad];
first = YES;
initialState = YES;
nrGooglePosts = 0;
[self.myMapView setShowsUserLocation:YES ];
myMapView.centerCoordinate = myMapView.userLocation.coordinate;
locationManager = [[CLLocationManager alloc] init];
[locationManager setDelegate:self];
[locationManager setDistanceFilter:kCLDistanceFilterNone];
[locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
NSMutableArray *userL =[[NSUserDefaults standardUserDefaults] objectForKey:#"user"];
if([userL count] == 0) NSLog(#"user nu e salvat");
[[Utilities get] setName:[[userL valueForKey:#"name"] objectAtIndex:0]];
[[Utilities get] setPhone:[[userL valueForKey:#"phone"] objectAtIndex:0]];
[[Utilities get] setCode:[[userL valueForKey:#"code"] objectAtIndex:0]];
[[Utilities get] setUserId:[[userL valueForKey:#"userid"] objectAtIndex:0]];
centerAnnotation = [[MKPointAnnotation alloc] init];
MKPointAnnotation * pc = [[MKPointAnnotation alloc] init];
pc.coordinate = myMapView.centerCoordinate;
pc.title = #"Map Center";
pc.subtitle= [[NSString alloc] initWithFormat:#"%f, %f",pc.coordinate.latitude,pc.coordinate.longitude];
[self.myMapView addAnnotation:pc];
centerAnnotation = pc;
lgr= [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(handleGesture:)];
lgr.minimumPressDuration=0.1;
lgr.allowableMovement = 5;
lgr.delegate = self ;
[myMapView addGestureRecognizer:lgr];
panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handleGesture:)];
panGesture.delegate = self;
[myMapView addGestureRecognizer:panGesture];
pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(handleGesture:)];
pinchGesture.delegate = self;
[myMapView addGestureRecognizer:pinchGesture];
swipeGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleGesture:)];
swipeGesture.delegate = self;
[myMapView addGestureRecognizer:swipeGesture];
NSMutableArray * arr=[[NSUserDefaults standardUserDefaults ] objectForKey:#"locationList"];
if([arr count]){
for(int i = 0 ; i < [arr count] ; i++ ){
NSMutableDictionary * adr = [[arr objectAtIndex:i] mutableCopy];
if(adr){
CLLocationDegrees lat = [[adr objectForKey:#"latitude"] doubleValue] ;
CLLocationDegrees lon = [[adr objectForKey:#"longitude"] doubleValue] ;
CustomMKAnnotation *ann = [[CustomMKAnnotation alloc] init ];
CLLocationCoordinate2D coord = { lat, lon };
ann.coordinate = coord;
ann.title = [adr objectForKey:#"street"] ;
ann.subtitle = [[NSString alloc] initWithFormat:#"Nr:%# Bl:%# Sc:%#",[adr objectForKey:#"number"],[adr objectForKey:#"bloc"],[adr objectForKey:#"scara"]];
MKAnnotationView *aux = [[MKAnnotationView alloc] initWithAnnotation:ann reuseIdentifier:nil];
UIImage *poza = [UIImage imageNamed:#"star.png"];
UIImageView *pic = [[UIImageView alloc] initWithImage:poza];
[aux addSubview:pic];
aux.canShowCallout = YES;
[myMapView addAnnotation:aux.annotation];
}
}
}
google = YES;
json = [self getLocationFromGoogleWithCoordinates:myMapView.userLocation.coordinate];
NSString *status = [[NSString alloc] initWithFormat:#"%#",[json objectForKey:#"status"]];
if([status compare:#"ZERO_RESULTS"] == 0 && [status compare:#"OVER_QUERY_LIMIT"] == 0)
{
google=NO;
NSLog(#"%#",status);
}
continuousLabel = [[MarqueeLabel alloc] initWithFrame:CGRectMake(32, 20, 191, 20) rate:50.0f andFadeLength:10.0f];
continuousLabel.marqueeType = MLContinuous;
continuousLabel.numberOfLines = 1;
continuousLabel.opaque = NO;
continuousLabel.enabled = YES;
continuousLabel.shadowOffset = CGSizeMake(0.0, -1.0);
continuousLabel.textAlignment = UITextAlignmentLeft;
continuousLabel.backgroundColor = [UIColor clearColor];
continuousLabel.font = [UIFont boldSystemFontOfSize:13];
continuousLabel.text = [[Utilities get] streetName];
[continuousLabel setBackgroundColor:[UIColor clearColor]];
[continuousLabel setTextColor:[UIColor whiteColor]];
continuousLabel.opaque = NO ;
myLoc.opaque=NO;
[myLoc setBackgroundColor:[UIColor clearColor]];
[self.view addSubview:continuousLabel];
[logoutButton setTitle:#"Log Out" forState:UIControlStateNormal];
[logoutButton addTarget:self action:#selector(logout:) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *logoutBarButton = [[UIBarButtonItem alloc] initWithCustomView:logoutButton];
self.navigationItem.leftBarButtonItem = logoutBarButton;
[self.navigationController.navigationBar setBackgroundColor:[UIColor clearColor]];
}
- (void) viewWillDisappear:(BOOL)animated
{
[self.navigationController setNavigationBarHidden:YES animated:animated];
[self stopTrackingLocation];
[myMapView removeAnnotations:myMapView.annotations];
self.myMapView.delegate = nil;
self.view = nil;
[super viewWillDisappear:animated];
}
- (void)stopTrackingLocation
{
if (myMapView.showsUserLocation)
{
// Crashes here
myMapView.showsUserLocation = NO;
}
}
As I see you are using ARC.
Hey man, do not do this:
self.view = NULL. //REMOVE THIS!!!!
You cannot push UIViewController again, because there is no UIVIew related to it. It will make a crash in UINavigationController, because there is nothing actually to push.
The second problem, which doesn't make crash but have a place.
You are removing Map View delegate. But if you are going to push this controller again, the second time map view will be disabled.
You should move this functionality to the dealloc method.
And you should show user location in viewWillAppear: method, not in viewDidLoad: because this method will be executed only once. It will not take effect, when you will try to push your UIVIewController second time. So please change this functionality:
- (void) viewWillAppear:(BOOL)animated{
[self.myMapView setShowsUserLocation:YES ];
}
- (void) viewWillDisappear:(BOOL)animated
{
[self.navigationController setNavigationBarHidden:YES animated:animated];
[self stopTrackingLocation];
[myMapView removeAnnotations:myMapView.annotations];
[super viewWillDisappear:animated];
}
-(void) dealloc{
self.myMapView.delegate = nil;
//In ARC we don't call [super dealloc]
}

presentModalView not shown when called inside delegate

I have a UIViewController called MainViewController (it is inside a navigationController). I have another UIViewController called OptionsViewController. Inside OptionsViewController I have a logout button and when clicked it calls a delegate in the MainViewController:
- (IBAction) logout:(id)sender
{
[self.delegate viewController:self loginSuccess:YES]; //calls this delegate
NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];
NSString * username = [standardDefaults stringForKey:#"kApplicationUserNameKey"];
NSError * error = nil;
[standardDefaults removeObjectForKey:#"kApplicationUserNameKey"];
[SFHFKeychainUtils deleteItemForUsername:username andServiceName:#"convore" error:&error];
[self dismissModalViewControllerAnimated:YES];
}
The delegate called at MainViewController is:
- (void) viewController:(OptionsViewController*)viewCon loginSuccess:(BOOL)loadFlag
{
if (loadFlag){
LoginViewController* lvc = [[LoginViewController alloc] init];
lvc.delegate = self;
[self.navigationController presentModalViewController:lvc animated:YES];
//this same code works in the viewDidLoad (it presents the LoginViewController, but not here)
[lvc release];
[self.groups removeAllObjects];
[self.table reloadData];
Topic * topic = [Topic object];
topic.tid = [NSNumber numberWithInt:-2];
self.detailViewController.topic = topic;
self.detailViewController.detailItem = topic.tid;
}
}
The issue is that when this delegate is called, it should present a LoginViewController (as can be seen from the code above), however it doesn't. I tried to put the presentModalViewController code in the delegate inside the viewDidLoad of MainViewController and it shows up, but when trying to show it in this delegate it doesn't. Why is this? And yes I checked the delegate is getting called (tried putting a NSLog inside the delegate)
UPDATE:
The OptionsViewController is shown as a modalViewController as well with the following code from MainViewController:
- (IBAction)showOptions:(id)sender
{
if ([self.detailViewController.message isFirstResponder])
[self.detailViewController setViewMovedUp:NO];
OptionsViewController * opt = [[OptionsViewController alloc] init];
opt.delegate = self;
opt.mgvc = self;
UINavigationController * uinc = [[UINavigationController alloc] initWithRootViewController:opt];
uinc.navigationBar.tintColor = [UIColor blackColor];
uinc.modalPresentationStyle = UIModalPresentationFormSheet;
uinc.title = #"";
uinc.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal; //transition shouldn't matter
[self presentModalViewController:opt animated:YES];
float xCenter = 384;
float yCenter = 512;
if (self.splitViewController.interfaceOrientation == UIInterfaceOrientationPortrait || self.splitViewController.interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown){
xCenter = 384;
yCenter = 512;
} else if (self.splitViewController.interfaceOrientation == UIInterfaceOrientationLandscapeLeft || self.splitViewController.interfaceOrientation == UIInterfaceOrientationLandscapeRight){
xCenter = 512;
yCenter = 384;
}
uinc.view.superview.frame = CGRectMake(0, 0 , 318, 209);//it's important to do this after presentModalViewController
uinc.view.superview.center = CGPointMake(xCenter, yCenter);
[opt release];
}
When I try to just show OptionsViewController itself (without the UINavigationController, everything works fine). Why is this?
Are you sure your view is inside a navigation controller? If not, change the line to:
[self presentModalViewController:lvc animated:YES];

using PDFScroller with a navigationController

I am trying to use this PDFScroller code http://dl.dropbox.com/u/5391413/PDFScroller.zip (thanks jbm). I would like to display a pdf from a list (a tableview) thanks to a navigationController. I init a PhotoViewControler with a pdf file name and display it correctly. The problem is that after I have loaded a file once, I don't manage to clean the pdfDoc ref and this causes a crash after coming back to the view list and loading another file.
I tried to release the pdfDoc ref, or set to nil in the PhotoViewController dealloc method but it does not work.
One more thing: the viewDidUnload method of the PhotoViewController is not called when popping the viewController out of the navigationcontroller stack... is that normal?
thanks
G.
here is how I launch a PhotoViewController from he root viewController:
PhotoViewController *detailViewController = [[PhotoViewController alloc] initWithNibName:#"PhotoViewController" bundle:nil pdfName:tmpName];
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
tmpName contains the name of the pdf file, I set a property in the PhotoViewController.Here is the PhotoViewController implementation (little different from the original sample code):
- (void)loadView
{
// Step 1: make the outer paging scroll view
CGRect pagingScrollViewFrame = [self frameForPagingScrollView];
pagingScrollView = [[UIScrollView alloc] initWithFrame:pagingScrollViewFrame];
pagingScrollView.pagingEnabled = YES;
pagingScrollView.backgroundColor = [UIColor blackColor];
pagingScrollView.showsVerticalScrollIndicator = NO;
pagingScrollView.showsHorizontalScrollIndicator = NO;
pagingScrollView.contentSize = CGSizeMake(pagingScrollViewFrame.size.width * [self pdfPageCount],
pagingScrollViewFrame.size.height);
pagingScrollView.delegate = self;
self.view = pagingScrollView;
// Step 2: prepare to tile content
recycledPages = [[NSMutableSet alloc] init];
visiblePages = [[NSMutableSet alloc] init];
[self tilePages];
}
- (void)viewDidUnload
{
[super viewDidUnload];
[pdfName release];
pdfName = nil;
[pagingScrollView release];
pagingScrollView = nil;
//CGPDFDocumentRelease(__pdfDoc);
//__pdfDoc = nil;
[recycledPages release];
recycledPages = nil;
[visiblePages release];
visiblePages = nil;
}
- (void)dealloc
{
NSLog(#"dealloc");
[pdfName release];
[pagingScrollView release];
[super dealloc];
}
- (void)tilePages
{
// Calculate which pages are visible
CGRect visibleBounds = pagingScrollView.bounds;
int firstNeededPageIndex = floorf(CGRectGetMinX(visibleBounds) / CGRectGetWidth(visibleBounds));
int lastNeededPageIndex = floorf((CGRectGetMaxX(visibleBounds)-1) / CGRectGetWidth(visibleBounds));
firstNeededPageIndex = MAX(firstNeededPageIndex, 0);
lastNeededPageIndex = MIN(lastNeededPageIndex, [self pdfPageCount] - 1);
// Recycle no-longer-visible pages
for (ImageScrollView *page in visiblePages) {
if (page.index < firstNeededPageIndex || page.index > lastNeededPageIndex) {
[recycledPages addObject:page];
[page removeFromSuperview];
}
}
[visiblePages minusSet:recycledPages];
// add missing pages
for (int index = firstNeededPageIndex; index <= lastNeededPageIndex; index++) {
if (![self isDisplayingPageForIndex:index]) {
ImageScrollView *page = [self dequeueRecycledPage];
if (page == nil) {
page = [[[ImageScrollView alloc] init] autorelease];
}
[self configurePage:page forIndex:index];
[pagingScrollView addSubview:page];
[visiblePages addObject:page];
}
}
}
- (void)configurePage:(ImageScrollView *)page forIndex:(NSUInteger)index
{
page.index = index;
page.frame = [self frameForPageAtIndex:index];
// Use tiled images
[page displayTiledImageNamed: [self pdfPage: index]
size: [self pdfSize: index]];
}
static CGPDFDocumentRef __pdfDoc = nil;
- (CGPDFPageRef) pdfPage: (NSInteger) index {
if( ! __pdfDoc ) {
NSString *pdfPath = [[NSBundle mainBundle] pathForResource: pdfName ofType:nil];
CFURLRef url = CFURLCreateWithFileSystemPath( NULL, (CFStringRef)pdfPath,
kCFURLPOSIXPathStyle, NO );
__pdfDoc = CGPDFDocumentCreateWithURL( url );
}
if( __pdfDoc ) {
size_t pdfPageCount = CGPDFDocumentGetNumberOfPages( __pdfDoc );
index++; // incoming param is zero-based, CGPDF calls are 1-based
if( index < 1 )
index = 1;
if( index > pdfPageCount )
index = pdfPageCount;
CGPDFPageRef page = CGPDFDocumentGetPage( __pdfDoc, index );
return page;
}
return nil;
}
-(IBAction)backToListView{
[self.navigationController popViewControllerAnimated:YES];
}
The problem is: in the - (CGPDFPageRef) pdfPage: (NSInteger) index method, __pdfDoc remains the same even after the PhotoViewController was popped off the navigationController stack, and this causes a crash. I don't where to clean it correctly.
thanks
Guillaume