So I'm on my first iPhone app. I'm actually rather far into it. I have already learned from many mistakes, but I feel I've made an ultimate mistake. I'm using segues to navigate to different views. I get into about 5 segue views deep, which I'm realizing is causing a LOT of allocated memory. In other words, View A calls View B, B segues into C, C into D, etc..From what I understand, by the time I get to D I now have instances of A B C and D open, which does not sound good. I am using delegates for example like below:
Just an example of what I'm doing throughout my app:
First View:
#interface FirstViewController : UIViewController<SecondViewControllerDelegate>
#end
Second View:
#class SecondViewController;
#protocol SecondReviewOrderViewControllerDelegate <NSObject>
- (void)secondViewControllerDidCancel:(SecondViewController *)controller;
#end
#interface SecondViewController : UIViewController<ThirdViewControllerDelegate>
#property (strong, nonatomic) id <SecondViewControllerDelegate> delegate;
#end
Third View:
#class ThirdViewController;
#protocol ThirdReviewOrderViewControllerDelegate <NSObject>
- (void)thirdViewControllerDidCancel:(ThirdViewController *)controller;
#end
#interface ThirdViewController : UIViewController<>
#property (strong, nonatomic) id <ThirdViewControllerDelegate> delegate;
#end
And so on and on onto view 4 and 5.
My question is, if this is wrong, which it seems to be, what is the right way to about navigating views and passing data from one viewcontroller to another? Thanks for any tips.
From what I understand, by the time I get to D I now have instances of A B C and D open, which does not sound good
A view controller, of itself, is a fairly lightweight object, and there is no problem whatever with going many levels deep (e.g. pushing five view controllers onto a navigation controller stack). However, memory and images you may be holding on to are not lightweight, so be sure to implement didReceiveMemoryWarning and take it seriously if it arrives.
A strategy for letting go of large retained memory-hogging stuff in response to didReceiveMemoryWarning is to save it off to disk (if it can't be recreated on demand) and then use lazy initialization to read it back in the next time you are asked for it.
Related
I have a UIView which is part of a UIPageViewController.
I pass a strong object to this view, and am having problem with releasing.
In the past I think I used viewDidUnload to release any strong objects, and then Dealloc is called. Now deal is never called because of the strong objects.
What is the best way to know icm with a UIPageViewController that the object is not needed anymore. I.e. if it is the view beside the page the user is looking at, it might come back into view. So using viewWillDisappeart will not work I expect.
#interface DOTourFloorPlanViewController : UIViewController <UIScrollViewDelegate, DOAsyncImageViewDelegate> {
IBOutlet DOAsyncImageView* _imageView;
IBOutlet UIScrollView* _scrollView;
NSMutableArray* _beaconLabels;
UIView* _circle;
UIView* _centerDot;
DOTour* _tour;
CGRect _zoomRect;
int _circleCenterX;
int _circleCenterY;
bool _didZoomToLocation;
}
#property (strong, nonatomic) DOTour* tour;
Views aren't unloaded any more, newer devices don't have quite such tight memory restrictions and there are other optimisations. It seems that when you say view you're actually referring to the view controller, which is a little confusing.
If your view controller (VC) is provided with some data it can retain a reference to it until it's destroyed. The data should not be retaining the VC, or its view. If you have any kind of observation / delegation then that link should be weak to prevent retain cycles.
In this way the data will be released when the VC is no longer required, i.e. when it is removed from its parent or presenter.
Specifically for Core Data and references to NSManagedObjects you can help the system by calling refreshObject:mergeChanges: with a flag of NO to turn the object into a fault and remove its data from memory. You can do this when the view did disappear.
So, I am looking at the code from Parse Anypic tutorial here
and my question is this :
There are these 2 view controllers :
#interface PAPHomeViewController : PAPPhotoTimelineViewController
#end
and this one :
#interface PAPPhotoTimelineViewController : PFQueryTableViewController <PAPPhotoHeaderViewDelegate>
- (PAPPhotoHeaderView *)dequeueReusableSectionHeaderView;
#end
I have a segue let's say that opens the homeViewController.
What is the relationship between these two? Both of the viewcontrollers have implemented the viewDidLoad function - and they are both called. In what order are they called? Is any of them having priority over the other? I do not understand the idea of a viewcontroller that extends another viewcontroller.
Can I have my HomeViewController extends the UIViewController and the PhotoTimeline to be initiated inside the HomeViewController, given a specific frame?
Presumably PAPHomeViewController is the one you are actually instantiating. If that's the case, then its viewDidLoad gets called, if it has one. If PAPHomeViewController calls [super viewDidLoad] within its viewDidLoad method then PAPPhotoTimelineViewController will be called at that point. In turn, if PAPPhotoTimelineViewController calls [super viewDidLoad] then PFQueryTableViewControllers viewDidLoad will be called.
This process will continue all the way up to UIViewControllers viewDidLoad method.
You asked
What is the relationship between these two?
I strongly suggest you stop programming for a bit and read up on basic programming principles. Especially read anything you can find on "implementation inheritance".
TLDR
Properties are not showing on a UIViewController that I was able to access when working on this project yesterday. This is not as simple as how do I set a property on a VC? I can not see the properties of the VC.
The Situation
A custom UIViewController (A) pushes to a second UIViewController (B), pushes to a third UIViewController (C)
//programmatically calling a push to the next view in A to B to C, example code from B to C.
EnterFinalHRViewController * finalHeartRate = [self.storyboard instantiateViewControllerWithIdentifier:#"EnterFinalHeartRateController"];
finalHeartRate.lanes = _lanes;
[self.navigationController pushViewController:finalHeartRate animated:YES];
The NSMutableArray, lanes, gets passed along twice. Not a problem.
When I arrive in VC(C) the debugger reads:
A self = (EnterFinalHRViewController *) #"0 objects" 0x15da40c0
V [0]
I have a header file in VC(C) that reads
#import <UIKit/UIKit.h>
#import "SwimTimingViewController.h"
#import "Lane.h"
#interface EnterFinalHRViewController : UIViewController <UICollectionViewDelegate, UICollectionViewDataSource, UIPickerViewDataSource, UIPickerViewDelegate>
#property (nonatomic, strong) NSMutableArray *lanes;
#end
For Clarity
Lanes is just an example of one property that is passed along.
This is not just trying to set and access a property of a VC across a segue
I've looked everywhere I can, any more links would be appreciated as well.
The Question
Why can't I see any properties of self in the final UIViewController in the debugger, how would one fix it, and or any useful debugging tips.
My Theory
Since upgrading to a new version of xcode, last night, something broke / xcode bug, and I don't know what that is. I am now using Xcode Version 6.1 (6A1052d). I am testing using my iPhone 5c running ios7. (I will be upgrading as soon as everything works 100% in ios7).
Quick shout out to thank all the contributors here at SO and beyond. The help is alway very warmly welcomed.
I have an application where I have 3 UINavigation Stacks that can be switched between each other via a custom menu. When switching from Stack A to either Stack B or C, it looks like the new section is being pushed onto the current navigation stack, as the RootViewController for Stacks B/C both have back buttons that pop back to the previous stack. User's can either navigate back to Stack A using the custom menu, or by hitting the back button on Stack B/C RootViewController, which brings them back to where they were in Stack A.
The problem I'm having is figuring out the best way to keep track of whether a user is in Stack A. If they are on the 4th drill down in Stack A, switch to Stack B, and then switch back to Stack A, I need to show exactly where they previously were in Stack A's flow.
Should I be using multiple UINavigationControllers, or is there perhaps a way to achieve this without as much hassle (i.e. possibly using UIViewController Containment)?
You could use containment to somehow change the navigation controller, yes, but you certainly don't need to do that. You can grab the whole stack within a UINavigationController before replacing it and keep track of your 3 stacks, in a structure like an array or dictionary.
typedef {
Section1,
Section2,
Section3
} Section;
..
#property (nonatomic, assign) Section currentSection;
#property (nonatomic, strong) NSMutableArray currentStacks; //Initialize this was the base stacks for each section (i.e an NSArray with just 1 controller for each slot)
#property (nonatomic, strong) UINavigationController *navigationController;
..
- (void)setSection:(Section)section
{
self.stacks[self.currentSection] = [self.navigationController.controllers copy];//Save stack for the current section
[self.navigationController setViewController:self.stacks[section] animated:YES];
self.currentSection = section;
}
As long as you don't have any problems with performance, my proposition is to keep all required view controller stacks inside separate UINavigationControl-s. So you would have as many navigation controller objects as items in your menu. In this case you would have rather less problems and your logic would be cleaner.
This approach doesn't require much memory, because the most consumable thing is UIView hierarchy and not UIViewController-s or UINavigationController-s.
Got a question, I'm trying to return to a previous view and share some data over to the frame I'm returning to. The data will be date and time and I would like to send this to a textField.
For example I'm calling the date *returneddate and the textField I'm calling *dateTime. The views are call *PickDateTime and SubmitEventsP2.
If you need more information just ask me and I'll add it if I can to make it easier for you to help me.
I'm using Xcode 4.2.
Ok.. its pretty simple.. you should use a delegate... if i understood correctly, you are on a secondary view and when you return to the main view you wish to send the data from the second view back to the main view, right?
so, in your second view, in the .h file, on top of interface, you will declare the delegate with:
#class nameOfTheViewController;
#protocol nameOfTheViewControllerDelegate <NSObject>
-(void)methodNameOfDelegateReturning:(NSString *)string otherString:(NSString *)string2;
#end
And in your interface, still in the .h, you will create a reference of this delegate like:
#property(nonatomic, weak) id <nameOfTheViewControllerDelegate> delegate;
after that, in your .m of nameOfTheViewController you will do:
#synthesize delegate = _delegate;
After you created you delegate in the nameOfTheViewController file, you will call the delegate method you just created exactly where and when you want to return to the previous view, filling it with the parameters you want to pass back... and of course, in your mainViewController, right in your didPrepareForSegue method, you will create a instance of the nameOfTheViewController class and set its delegate proeprty to self... for this to be possible, in your mainViewController .h you must conform to the nameOfTheViewControllerDelegate protocol.