I have a problem with big memory leaks when I use UIPageViewController. I have a view and I scroll it. I see that memory grows very fast.
I think that is the problem:
- (ViewControllerEvent *)viewControllerAtIndex:(NSUInteger)index {
ViewControllerEvent *childViewController = [[UIStoryboard storyboardWithName:[self isIPad]?#"Main_iPad":#"Main_iPhone" bundle:nil] instantiateViewControllerWithIdentifier:#"ViewControllerEvent2"];
childViewController.index = index;
childViewController.event = [self.events objectAtIndex:index];
return childViewController;
}
My class:
#interface ViewControllerEvent : UIViewController
#property (assign, nonatomic) NSDictionary *event;
#property (assign, nonatomic) NSInteger index;
#property (weak, nonatomic) IBOutlet UIImageView *header;
#property (weak, nonatomic) IBOutlet UIScrollView *_scrollViewDesc;
#property (retain, nonatomic) IBOutlet UITextView *descLabel;
#property (retain, nonatomic) IBOutlet UIView *whiteBackground;
#property (weak, nonatomic) IBOutlet UIImageView *bootomMapImage;
#end
I use about 100 views in my pager.
Memory leaks are usually related to keeping strong references to some object which should have a weak reference, delegates for instance. Either that or you're keeping references to each child view controller, thereby growing the size of memory.
Don't use an instance method to vend view controllers for the page view controller; use a class method instead.
+ (ViewControllerEvent *)viewControllerAtIndex:(NSUInteger)index
{
…
return childViewController;
}
Related
My app crashes with this stack trace:
[DictationDetailsController respondsToSelector:]: message sent to deallocated instance
I tracked that on instruments trying to see the relevant code causing the crash:
here is the relevant code for MyDictationController in the didSelectRowAtIndexPath: delegate method:
- (void)tableView:(UITableView )tableView didSelectRowAtIndexPath:(NSIndexPath )indexPath {
DictationDetailsController *controller = GET_CONTROLLER_WITH_CLASS([DictationDetailsController class]);
controller.dictation = [unSubmittedDictations objectAtIndex:indexPath.row];
controller.isEditMode = YES;
controller.selectedDate = _selectedDate;
controller.hidesBottomBarWhenPushed = YES;
[self.navigationController pushViewController:controller animated:YES];
}
#property (copy ,nonatomic) Dictation *dictation;
Also i have used #synthesize. Help me out in this issue, to get which deallocated method is being called.?
Here's my DictationDetailsController interface:
#interface DictationDetailsController : BaseController
#property (copy ,nonatomic) Dictation *dictation;
#property (nonatomic) BOOL isEditMode;
#property (nonatomic) NSDate *selectedDate;
#property (weak, nonatomic) IBOutlet UILabel *navigationTitleLabel;
#property (weak, nonatomic) IBOutlet UITextField *patientNameTextField;
#property (weak, nonatomic) IBOutlet UITextField *accountIDTextField;
#property (weak, nonatomic) IBOutlet UITextField *workTypeTextField;
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *deleteButtonWidth;
#property (weak, nonatomic) IBOutlet UIView *tutorialView;
#property (weak, nonatomic) IBOutlet UIView *audioContainer;
#property (weak, nonatomic) IBOutlet UISlider *audioSlider;
#property (weak, nonatomic) IBOutlet UILabel *durationLabel;
#property (weak, nonatomic) IBOutlet UILabel *noRecordingLabel;
#property (weak, nonatomic) IBOutlet UIButton *playPauseButton;
#end
And in dealloc method:
- (void)dealloc {
[player pause];
player = nil;
self.dictation = nil;
}
My guess is the issue is somewhere inside GET_CONTROLLER_WITH_CLASS method. Pop a breakpoint on that line and step over it. It's possibly producing a released instance of the class. That being the case, the crash would occur on the line immediately following the call to that method when it tries to access the dictation property.
I currently have a header that displays a name, time, and a couple of buttons. This header should only appear if an appointment is selected in a dashboard, which is irrelevant here. However, once i logout and log back in, with no patient selected, the header view is displayed. I think this is because I did not deallocate the appointment object, and i'm not sure how to do that (i'm new to iOS programming).
Here's my code:
So I have the interface
#interface DashboardVC : CommonVC <UIActionSheetDelegate, HeaderViewDelegate, PracticeServiceDelegate> {
IBOutlet HeaderView *_headerView;
}
And inside the HeaderView object i have these properties:
#property (strong, nonatomic) CCAppointment *appointment;
#property (strong, nonatomic) IBOutlet UIButton *backButton;
#property (strong, nonatomic) IBOutlet UIView *currentPatientView;
#property (strong, nonatomic) IBOutlet UIImageView *avatarImageView;
#property (strong, nonatomic) IBOutlet UILabel *patientNameLabel;
I then, in dashboard VC, want to deallocate, but i'm not sure how... this is what i have:
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
How do I deallocate the properties so that the headerVIew does not show up?
if you want to destroy _headerView try:
[_headerView removeFromSuperview];
_headerView = nil;
I found a lot of how to use methods of chlidViewController. But I couldn't find how to change and set value of uitextfield and uiswitch from childViewController.
ChildViewController.h:
#protocol VVInformationTableViewControllerDelegate;
#interface VVInformationTableViewController : UITableViewController
#property (weak, nonatomic) id<VVInformationTableViewControllerDelegate> delegate;
#property (weak, nonatomic) IBOutlet UITextField *nameTextField;
#property (weak, nonatomic) IBOutlet UITextField *surnameTextField;
#property (weak, nonatomic) IBOutlet UITextField *emailTextField;
#property (weak, nonatomic) IBOutlet UITextField *locationTextField;
#property (weak, nonatomic) IBOutlet UITextField *headlineTextField;
#property (weak, nonatomic) IBOutlet UITextField *positionTextField;
#property (weak, nonatomic) IBOutlet UITextField *companyTextField;
#property (weak, nonatomic) IBOutlet UISwitch *messagesEnable;
#end
ParentViewControler.m:
- (void)viewDidLoad
{
self.currentAttendee = [VVAPIClient sharedClient].currentUser;
NSParameterAssert(self.currentAttendee);
[super viewDidLoad];
[self.navigationController setNavigationBarHidden:YES];
self.infoTableController = [[VVInformationTableViewController alloc] initWithNibName:#"InformationTableViewController" bundle:nil];
[self addChildViewController:self.infoTableController];
}
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
self.infoTableController.nameTextField.text = self.currentAttendee.firstName?:#"";
self.infoTableController.surnameTextField.text = self.currentAttendee.lastName?:#"";
self.infoTableController.emailTextField.text = self.currentAttendee.email?:#"";
self.infoTableController.locationTextField.text = self.currentAttendee.location?:#"";
self.infoTableController.headlineTextField.text = self.currentAttendee.headline?:#"";
self.infoTableController.positionTextField.text = self.currentAttendee.position?:#"";
self.infoTableController.companyTextField.text = self.currentAttendee.company?:#"";
}
-(void)viewDidLayoutSubviews{
self.infoTableController.messagesEnable.on = NO;
self.infoTableController.nameTextField.tag = 0;
self.infoTableController.surnameTextField.tag = 1;
self.infoTableController.emailTextField.tag = 2;
self.infoTableController.locationTextField.tag = 3;
self.infoTableController.headlineTextField.tag = 5;
self.infoTableController.positionTextField.tag = 6;
self.infoTableController.companyTextField.tag = 7;
}
Thanks for help.
As david says in his comment, don't.
It violates the encapsulation of the other view controller, and leads to spaghetti code.
You should treat another VCs (View Controller's) views as private.
What you should do is add properties to the child view controller to hold strings and other state data that you need to display. Then in your child view controller's viewWillAppear method, you can take the settings and apply them to your view hierarchy.
In your case, since what you're doing is displaying a whole bunch of information about "currentAttendee", (which I guess is a model object) you might want to think about passing a pointer to the whole attendee object to the child, and letting it display the information itself.
Or, of the child can edit the object, you might want to pass a copy, and use a delegate method when you want to commit the changes made in the child, or simply return if you want to discard changes.
so I'm writing Obj-C for iOS, and something "strange" is happening..
I have an MVC, with a UITableView (private):
#interface MVC ()
#property (strong, nonatomic) IBOutlet UITableView *tableView;
#property (strong, nonatomic) CellVC *cell1;
#property (strong, nonatomic) CellVC *cell2;
#end
I load the table view up with a few custom cells. My custom cell class is actually a UIViewController... so I instantiate a few, and set cell.contentView to the corresponding CellVC.view inside the tableView:cellForRowAtIndexPath: method. My custom cell class:
#interface CellVC : UIViewController
#property (strong, nonatomic) IBOutlet UIKnob *knob1;
#property (strong, nonatomic) IBOutlet UIKnob *knob2;
#property (strong, nonatomic) IBOutlet UIKnob *knob3;
#property (strong, nonatomic) IBOutlet UIKnob *knob4;
#end
In case you're wondering, I've written a subclass of UIControl named UIKnob...
In CellVC's viewDidAppear: method, I've set a breakpoint to check the values of every knob. Each knob is non-nil, so I am happy... they have all been created.
My goal is to set MVC as the delegate of each knob. (4 knobs for each cell)
If I set a breakpoint anywhere in MVC, the value of each knob is nil??...
cell1.knob1.delegate = self;
will not work because the knobs only exist inside CellVC.m ...
Any ideas??
Okay, I have a basic understanding of what is happening here, but am having trouble fixing it. I am hoping someone can walk me through what I'm doing wrong here...
I have a nifty app that works great and was built with the storyboard and custom UIViewControllers to handle all my code. I was doing really well, until I needed to handle my push notifications by dropping me in a specific view and loading some data. I made a lot of headway today and just got stuck in a bad way. I am now getting an objc_sendmsg error and I know it has to do with my memory management. I've never initialized a view in this way, so I'm wondering if that's what's causing it. Basically, I can load a view, but I can never push any buttons or get anywhere after that.
Here's the code:
AppDelegate.m
UIStoryboard* storyBoard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
UIViewController *detailVC = [storyBoard instantiateViewControllerWithIdentifier:#"Leads_Calls_SB"];
[self.window addSubview:detailVC.view];
[[NSNotificationCenter defaultCenter] postNotificationName:#"callReceived"
object:nil
userInfo:userInfo];
[self.window makeKeyAndVisible];
Leads_CallsDetailViewController.h
#property (strong, nonatomic) IBOutlet UILabel *cName;
#property (strong, nonatomic) IBOutlet UILabel *cStart;
#property (strong, nonatomic) IBOutlet UILabel *cNumber;
#property (strong, nonatomic) IBOutlet UILabel *cStart2;
#property (strong, nonatomic) IBOutlet UILabel *cEnd;
#property (strong, nonatomic) IBOutlet UILabel *cDuration;
#property (strong, nonatomic) IBOutlet UILabel *cStatus;
#property (strong, nonatomic) IBOutlet UILabel *cProvider;
#property (strong, nonatomic) IBOutlet UILabel *cLineType;
#property (strong, nonatomic) IBOutlet UILabel *cCity;
#property (strong, nonatomic) IBOutlet UIView *innerView;
#property (strong, nonatomic, retain) IBOutlet UIButton *backStyle;
#property (strong, nonatomic) IBOutlet UIScrollView *scrollView;
#property (strong, nonatomic, retain) NSString *cNotifID;
#property (strong, nonatomic, retain) NSString *cNameText;
#property (strong, nonatomic, retain) NSString *cNumberText;
#property (strong, nonatomic, retain) NSString *cStartText;
#property (strong, nonatomic, retain) NSString *cEndText;
#property (strong, nonatomic, retain) NSString *cCallStatusText;
#property (strong, nonatomic, retain) NSString *cLatitudeText;
#property (strong, nonatomic, retain) NSString *cLongitudeText;
#property (strong, nonatomic, retain) NSString *cCityText;
#property (strong, nonatomic, retain) NSString *cLineTypeText;
#property (strong, nonatomic, retain) NSString *cProviderNameText;
- (IBAction)back:(id)sender;
#property (strong, nonatomic) IBOutlet MKMapView *map;
- (IBAction)forward_lead:(id)sender;
- (IBAction)call_lead:(id)sender;
- (IBAction)add_lead:(id)sender;
#property (strong, nonatomic) IBOutlet UIButton *bottomMessage;
#property (strong, nonatomic) IBOutlet UIButton *bottomCalls;
#property (strong, nonatomic) IBOutlet UIButton *bottomReports;
#property (strong, nonatomic) IBOutlet UIButton *bottomHome;
.m
- (IBAction)back:(id)sender {
if (self.cNotifID != nil)
{
[self.view removeFromSuperview];
}
else {
[self.navigationController popViewControllerAnimated:YES];
}
}
I'm not sure what I'm doing wrong, but no matter what happens if I hit any button on that page or try to dismiss the view, it screams at me and gets angry...I've tried everything I can think of to figure this out.
Thanks guys!
The issue is that you're creating your view controller, grabbing its view, but the letting the controller fall out of scope (and presumably using ARC where it's getting released on you).
In my original answer, I thought the goal was simply to consider different ways of presenting the standard initial view controller. But that is not the case. The question is how to present a new scene when some event takes place (in my example, I'm doing it upon openURL, but you could presumably do this in response to notifications and the like).
Anyway, one approach to solving this is to perform presentViewController. So you could do something like:
// determine the current controller (in case you've already done some modal segues)
UIWindow *window = [[UIApplication sharedApplication] keyWindow];
UIViewController *currentController = window.rootViewController;
while (currentController.presentedViewController)
currentController = currentController.presentedViewController;
// load the controller for the new scene
UIStoryboard* storyBoard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
UIViewController *newController = [storyBoard instantiateViewControllerWithIdentifier:#"Leads_Calls_SB"];
// perform a modal transition to the new scene
[currentController presentViewController:newController animated:NO completion:nil];