I write app on iOS. I've got main class and UIView subclass with some UILabel fields.
I want to release memory when objects of subclass are out of the screen (I hide view by animation). How can I do this?
ViewController.h
#import "Histogram.h"
#import "HistogramDelegate.h"
{
UIScrollView *filtersScrollView;
UITapGestureRecognizer *tapGesture;
UISwipeGestureRecognizer *swipeGesture;
...some UILabels and other components.
Histogram *_Histogram;
}
#property (nonatomic, retain) Histogram *_Histogram;
... other properties
... some functions
#end
ViewController.m
-(void)viewDidLoad {
_Histogram = [[Histogram alloc] initWithFrame:...];
}
-(void)viewDidUnload // here i add nil value to objects, for ex. UIScrollView = nil.
-(void)someFunc {
[_Histogram hideHistogram];
}
Histogram.h
//some objects/fields like UILabels, UISliders, UIViews
Histogram.m
some functions.
-(void)hideHistogram {
}
How and where can I release _Histogram and his objects from memory when are out of the screen? When I alloc and init _Histogram and when I hide _Histogram, my app is slower.
The question is not very clear. Anyways if you mean to ask how to free your memory once your histogram is hidden: then what you have to do is after calling [_histogram _hidden] call [_histogram release]; _histogram=nil;
Also in the dealloc function of your histogram.m file you should release all the elements you have initialized in that class. Otherwise releasing _histogram object wouldn't be of much help
Related
Im curious, where is the best option to allocate/init, set attributes of views (uibutton, uilabel, uitextfield, initializing variables, etc).
This is in regards to developing an app strictly programatically. I see some cases where these views have been allocated/init in the class -init method, but then other times i see other views set in the -loadview method.
Can anyone provide some clarity about this? And maybe some abstract examples of when the best time to do it for either method would be.
Thanks
The -init* family of functions would be a good place to initialize simple properties, e.g. strings, numbers, and the like. The initializer runs just after the memory for the object is allocated, and if you have something that can be initialized there then you should do it there.
For UIViewController instances, you probably have to wait until the nib has been loaded before you can initialize everything else. If you've got images that need to be placed inside subviews, or fonts that need configuring, or whatever, then you need to have the nib loaded first. -viewDidLoad is the best place for that stuff.
For UIView instances (or subclasses like UITableViewCell), you need to wait for the nib to be loaded too. You can use -awakeFromNib in that case.
Here's a quick comment on this:
-SubClass a UIView, smash all your UI elements into that view, well as many as you can at least. Import this subclassed view's header into your view controller's implementation file
-In your view controller, typecast your view controller's view like so:
-(HHYSignUpViewFirstPhase*)contentView
{
return (id)[self view];
}
-Invoke the loadView method
-(void)loadView
{
[self setView:[HHYSignUpViewFirstPhase new]];
}
-In your viewdidLoad, you can now set handlers to buttons and such from your subclassed UIView by calling to "[self contentView]" like so:
-(void)viewDidLoad
{
[super viewDidLoad];
[self setTitles:#"Sign Up"];
[[[self contentView] nameField] setDelegate:self];
[[[self contentView] emailField] setDelegate:self];
[[[self contentView] passwordField] setDelegate:self];
[[[self contentView] signupButton] addTarget:self action:#selector(signupPressed) forControlEvents:UIControlEventTouchUpInside];
}
Now you have it all set up, you just need to add methods to handle events from the button, for example in the view did load from your subview that you subclassed:
-(void)signupPressed
{
///do work
}
UIVIew subclass:
HHYSignUpViewFirstPhase.h
#interface HHYSignUpViewFirstPhase : UIView
#property (nonatomic) UIButton * signupButton;
#property (nonatomic) UITextField * emailField;
#property (nonatomic) UITextField * nameField;
#property (nonatomic) UITextField * passwordField;
#end
HHYSignUpViewFirstPhase.m
#import "HHYSignUpViewFirstPhase.h"
#implementation HHYSignUpViewFirstPhase
-(id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self == nil)
return nil;
//do work, set up buttons, constraints, etc, etc.
return self;
}
#end
Essentially, what I'm saying here is that in the subclassed UIView you can initialize the UIView and set up all its constraints and EVERYTHING, frames included and then in the load view method of your UIViewController, you then call to this view and typcast the view of the UIViewController. So, sometimes you do the set up in the init, sometimes you do it in the load view, it depends on what you are trying to do, but this is how you set this up in a pure programmatic fashion with separation of duties, encapsulation, and all tied together in an MVC framework -- all work is separated into classes, and all controllers control a single class.
http://matthewmorey.com/creating-uiviews-programmatically-with-auto-layout/
and this
https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/ViewLoadingandUnloading/ViewLoadingandUnloading.html#//apple_ref/doc/uid/TP40007457-CH10-SW36
I have a randomly generated int that I assign to a tag for a UIImageView on my storyboard in ViewWillAppear.
When I segue to the main menu and try to enter the view again, however, the app crashes. I know it's because of the tag because when I remove it everything works fine.
Any thoughts on why it works the first time but not on times after that? Code below.
ViewController.h:
#interface ViewController : UIViewController{
int tagnumber;
IBOutlet UIImageView *box;
...
}
ViewController.m:
-(void)viewWillAppear:(BOOL)animated{
tagnumber = arc4random()%1000;
box.tag = tagnumber;
...
}
- (IBAction)unwindToThisViewController:(UIStoryboardSegue *)unwindSegue
{
[_animator removeAllBehaviors];
[box removeFromSuperview];
}
MainMenu.m:
-(IBAction)prepareForUnwind:(UIStoryboardSegue *)segue {
}
Basically, when the view disappears and the system is running out of memory, it will call on UIViewController's implementation of didReceiveMemoryWarning. There is a fantastic description of this here: ViewWillDisappear versus dealloc
When you are creating an IBOutput you should really have a weak pointer to it by saying #property (weak, nonatomic) IBOutlet UIImageView *box. Views retain their subviews, and therefore, if a view gets deallocated, its subviews retain count decreases by one. When the view disappears, the system will decide when to deallocate self.view, and when it does, it will automatically release box, and box will get deallocated as well. You don't really need to worry about it.
It is one of my first days at iOS programming. I came from C++ and have specific silly question. How does compiler work and go through the code?
How I understand all starts with public interface, then continues to private. How implementation works? Methods? Is view controller as main function in C++ and it goes through all methods at the start?
Here is my viewController .h and .m. This program already has some other classes and action buttons. Maybe someone can explain step-by-step. Thanks.
ViewController.h
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#interface ViewController : UIViewController
#end
ViewController.m
#import "ViewController.h"
#import "Deck.h"
#import "PlayingCardDeck.h"
#interface ViewController ()
#property (weak, nonatomic) IBOutlet UILabel *flipsLabel;
#property (nonatomic) int flipCount;
#property (strong, nonatomic) Deck *deck;
#end
#implementation ViewController
- (Deck *)lol
{
if (!_deck) _deck = [self createDeck];
return _deck;
}
- (Deck *)createDeck
{
return [[PlayingCardDeck alloc] init];
}
- (void)setFlipCount:(int)flipCount{
_flipCount=flipCount;
_flipsLabel.text = [NSString stringWithFormat:#"Count: %d", _flipCount];
NSLog(#"%d", self.flipCount);
}
- (IBAction)touchCardButton:(UIButton *)sender {
if ([sender.currentTitle length]) {
[sender setBackgroundImage:[UIImage imageNamed:#"cardback"] forState:UIControlStateNormal];
[sender setTitle:#"" forState:UIControlStateNormal];
}
else {
Card *randomCard = [self.lol drawRandomCard];
if (randomCard){
[sender setBackgroundImage:[UIImage imageNamed:#"cardfront"] forState:(UIControlStateNormal)];
[sender setTitle:randomCard.contents forState:UIControlStateNormal];
self.flipCount++;
}
}
}
#end
The beginning of the program code is similar to c++, it is the very c main() function.
Within your main the framework is called (by instaticating an UIApplication or subclass object) and the names of the application class and the application delegate class are handed over to the framework. The cocoa touch framework will then instantiate the application first and instantiate the delegate and assign the delegate to the application.
Typcially the first method from your program code that is invoked is the UIApplicationDelegate method application:willFinishLaunchingWithOptions: but the one that you typcially start with is application:didFinishLaunchingWithOptions:
There some preparation is set up, which is often not required especially when you work with a storyboard or when you set the main interface in your project properties. According to these properties or storyboard one view controller is the root view controller that is invoked first. For the view controllers it is quite similar. You would use NIB files or storyboards in most cases to define their UI Items and then viewDidLoad is the first method that is being invoked with regard to the root view.
Given your code you are likely to add something like this:
-(void) viewDidLoad {
[super viewDidLoad];
[self createDeck]
// here you may want to access some UIView objects in order to display your deck.
}
I don't know if you understand how c++ compiles, Objective-C is all the same.
First preprocessor translate all preprocess code(#import, #macro, etc), and then every .m file is considered a compile unit, they are compile separately in to object files without a specific order.
Then linker links all object files together.
If you don't understand what compile unit or object file are, I suggest you do more research on how preprocessor, compiler, linker works, since it is a too broad topic to explain here.
I am a newbie learning "iPad and iPhone Application Development" course. In the demo of lecture 5, we have some code like this
#import "HappinessViewController.h"
#import "FaceView.h"
#interface HappinessViewController ()
#property (nonatomic, weak) IBOutlet FaceView *faceView;
#end
#implementation HappinessViewController
#synthesize happiness = _happiness;
#synthesize faceView = _faceView;
-(void) setHappiness:(int)happiness
{
_happiness = happiness;
[self.faceView setNeedsDisplay];
}
-(void)setFaceView:(FaceView *)faceView
{
_faceView = faceView;
NSLog(#"set FaceView invoked");
[self.faceView addGestureRecognizer:[[UIPinchGestureRecognizer alloc]
initWithTarget:self.faceView action:#selector(pinch:)]];
}
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return YES;
}
#end
in method "-(void)setFaceView:(FaceView *)faceView", I wonder it might be something similar to event listener in javascript. But I also want to know
when the event listener was bound. So I add "NSLog(#"set FaceView invoked");". It turns out that this setter function was invoked once I run this program which makes me really very confused. So I am wondering how "setFaceView" is invoked at the very beginning?
By the way, FaceView is a subclass of UIView and faceView is the only instance of FaceView class. And also I try to add "NSLog(#"set happiness invoked");" in method setHappiness, this
is not invoked at the very beginning of program.
If you have faceView bound to a view in a NIB or a Storyboard, then -setFaceView: is called when the NIB is loaded or the view controller is loaded by the Storyboard.
-setFaceView: is the setter for the faceView property. Whenever self.faceView = … is done, it's -setFaceView: that gets called.
I create an UITapGesture with a target which is NOT the current object. Later, when tapping, app crashes.
View controller .h:
#interface ViewController : UIViewController
{
IBOutlet UIImageView *iv;
}
#end
View controller .c:
#import "ViewController.h"
#import "Target.h"
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
Target *t = [[Target alloc] init];
UITapGestureRecognizer *tgr = [[UITapGestureRecognizer alloc] initWithTarget:t action:#selector(gestureDone:)];
[iv addGestureRecognizer:tgr];
[iv setUserInteractionEnabled:YES];
}
#end
Target.h:
#interface Target : NSObject
- (void)gestureDone:(UIGestureRecognizer *)gr;
#end
Target.c:
#implementation Target
- (void)gestureDone:(UIGestureRecognizer *)gr
{
NSLog(#"Gesture!");
}
#end
(My XIB file just contains one image...)
When tapping the image, it crashes. If for example I add an instance variable Target *t to my view controller (and remove local declaration in viewDidLoad), then no issue arises. When not doing that, I overrided dealloc in Target, put a NSLog there and saw that as soon as viewDidLoad finishes execution, the Target object is fred.
Am I doing anything wrong, or is it some issue? (Usually I'm not facing this problem because I use initWithTarget:self ...).
UIGestureRecognizer doesn't retain its target. Most objects that take a target/action pair do not retain their targets. This is mentioned in the Cocoa Fundamentals Guide/Communicating with Objects/The Target-Action Mechanism/The Target:
Control objects do not (and should not) retain their targets. However, clients of controls sending action messages (applications, usually) are responsible for ensuring that their targets are available to receive action messages. To do this, they may have to retain their targets in memory-managed environments. This precaution applies equally to delegates and data sources.
You need to make sure the target is retained some other way, such as by storing a reference to t in an instance variable of your ViewController.
Add an instance variable of the Target t to your ViewController class and make it strong. That way it stays in memory.