I have a method were I'm creating UIView and it works fine when I call it from IBAction. But when I call the same method again it draws another view on top and I believe it's a memory leak. How do I remove previous UIView before creating another one? Thanks!
- (int)showQuestionMethod:(int)number;
{
UIView *questionView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 250)];
questionView.backgroundColor = [[UIColor alloc] initWithRed:0.93 green:0.93
blue:0.93 alpha:1.0];
[self.view addSubview:questionView];
questionView.tag = questionNumber;
UILabel *questionLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 20, 280, 0)];
questionLabel.text = question1;
[questionView addSubview:questionLabel];
CGRect frame = questionView.frame;
frame.size.height = questionHeight;
questionView.frame = frame;
questionView.tag = questionNumber;
return currentQuestion;
}
- (IBAction)nextQuestion:(id)sender {
[self showQuestionMethod:questionNumber];
}
Create a property which will let you reference a view:
#property(nonatomic, strong) UIView *questionView;
Then change your method to remove the old view and create a new one:
- (int)showQuestionMethod:(int)number;
{
// Remove the previous view.
[_questionView removeFromSuperview];
// Create a new view.
_questionView= [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 250)];
_questionView.backgroundColor = [[UIColor alloc] initWithRed:0.93 green:0.93
blue:0.93 alpha:1.0];
// Add the view.
[self.view addSubview:_questionView];
_questionView.tag = questionNumber;
UILabel *questionLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 20, 280, 0)];
questionLabel.text = question1;
[_questionView addSubview:questionLabel];
CGRect frame = _questionView.frame;
frame.size.height = questionHeight;
_questionView.frame = frame;
_questionView.tag = questionNumber;
return currentQuestion;
}
The simplest way would be to keep a reference to the view you will want to remove (a private property would work nicely). You could add the code at bottom to the top of your controllers .m file:
#interface MyUIViewController ()
#property (nonatomic, strong) UIView* questionView;
#end
Then modify your method as follows:
- (int)showQuestionMethod:(int)number;
{
[self.questionView removeFromSuperview]
self.questionView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 250)];
self.questionView.backgroundColor = [[UIColor alloc] initWithRed:0.93 green:0.93
blue:0.93 alpha:1.0];
[self.view addSubview:self.questionView];
self.questionView.tag = questionNumber;
UILabel *questionLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 20, 280, 0)];
self.questionLabel.text = question1;
[self.questionView addSubview:questionLabel];
CGRect frame = questionView.frame;
frame.size.height = questionHeight;
self.questionView.frame = frame;
self.questionView.tag = questionNumber;
return currentQuestion;
}
use this before creating new view
[myview removeFromSuperview];
You can either keep a reference to the view by adding #property (strong, nonatomic) UIView *questionView; in your #interface declaration then call [_questionView removeFromSuperview]; to remove it.
Or, better yet, keep that reference to it then have a method to reload the info on it and animate it out/back into view (perhaps by fading out, reloading the data on it, then fading it back in). That way you aren't throwing away / recreating views all the time, and instead you're just reusing the same, already created view.
[self.questionView removeFromSuperview];
before adding the other view, remove this from the superview!
Why not reuse the view?
If you'd rather delete it every time and you don't want to keep a reference to it, you can always set (dirty but simple):
questionView.tag = SOME_CONST;
And then add in the beginning of your method:
[[self.view viewWithTag:SOME_CONST] removeFromSuperview];
I know this question has been answered, but i want to add a precaution that you before removing a UIView or anything else you should FIRST CHECK IF IT IS ALLOCATED. So the removal should be like:
// Make property first
#property (nonatomic, strong) UIView *questionView;
- (int)showQuestionMethod:(int)number;
{
// Check it it is allocated
if(questionView)
{
[questionView removeFromSuperView];
//[questionView release]; // Un-Comment it if NOT using ARC
questionView = nil;
}
// At this point you safe to create a new UIView.
questionView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 250)];
questionView.backgroundColor = [[UIColor alloc] initWithRed:0.93 green:0.93
blue:0.93 alpha:1.0];
[self.view addSubview:questionView];
questionView.tag = questionNumber;
UILabel *questionLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 20, 280, 0)];
questionLabel.text = question1;
[questionView addSubview:questionLabel];
CGRect frame = questionView.frame;
frame.size.height = questionHeight;
questionView.frame = frame;
questionView.tag = questionNumber;
return currentQuestion;
}
Hope the snippet and comment inside makes sense.
Happy Coding!!!
Related
Is it possible to place an UIView fixed but as collision-object? In my example is a box-view falling down and collide with the floor-view. I want the floor-view to stay at it's place but it's moving after it's been hit by the box.
How can I glue it in one place (I don't want to enlarge the object or use other objects than UIView (UIBezierPath etc)).
- (void)viewDidLoad {
[super viewDidLoad];
UIButton *start = [[UIButton alloc]initWithFrame:CGRectMake(200, 20, 40, 40)];
start.backgroundColor = [UIColor redColor];
[start addTarget:self action:#selector(start) forControlEvents:UIControlEventTouchUpInside];
[main addSubview:start];
self.box1 = [[UIView alloc]initWithFrame:CGRectMake(50, 0, 20, 20)];
self.box1.backgroundColor = [UIColor redColor];
[main addSubview:self.box1];
self.floor = [[UIView alloc]initWithFrame:CGRectMake(0, main.frame.size.height-20, main.frame.size.width, 200)];
self.floor.backgroundColor = [UIColor lightGrayColor];
[main addSubview:self.floor];
}
- (void) start {
self.animation = [[UIDynamicAnimator alloc]initWithReferenceView:self.view];
UIGravityBehavior *gravity = [[UIGravityBehavior alloc]initWithItems:#[self.box1]];
[self.animation addBehavior:gravity];
UICollisionBehavior *collision = [[UICollisionBehavior alloc]initWithItems:#[self.box1, self.floor]];
[self.animation addBehavior:collision];
}
One solution to your problem (which is a quite simple setup) could be to create an UIView that will serve as a reference view. Set it's frame so the bottom of the view will be your floor. Then add your box as a subview for that reference view, add collision behaviour with translatesReferenceBoundsIntoBoundary set to YES and you have a box falling on the floor.
// Reference view
CGRect referenceFrame = CGRectMake(0, 0, 320, 500); // the floor will be at y = 500
UIView *referenceView = [[UIView alloc] initWithFrame:referenceFrame];
[self.view addSubview:referenceView];
// Box
CGRect boxFrame = CGRectMake(50, 50, 10, 10);
UIView *boxView = [[UIView alloc] initWithFrame:boxFrame];
boxView.backgroundColor = [UIColor redColor];
[referenceView addSubview:boxView];
self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:referenceView];
// Gravity
UIGravityBehavior *gravity = [[UIGravityBehavior alloc] initWithItems:#[boxView]];
[self.animator addBehavior:gravity];
UICollisionBehavior *collision = [[UICollisionBehavior alloc] initWithItems:#[boxView]];
collision.translatesReferenceBoundsIntoBoundary = YES;
[self.animator addBehavior:collision];
You can provide a pretty visual for the floor outside of referenceView
I used UIDynamicItemBehavior for my view and set the following property to be true.
#property(nonatomic, getter=isAnchored) BOOL anchored;
This locked the UIView in place. Do what you were doing above to add the item to the behavior and add the behavior to the animator.
I have a UIViewController named MenuViewController in which i create an UIView MessageView and pass it a NSString:
MessageView *mess = [[MessageView alloc]initWithFrame:CGRectMake(0, 0, 1024, 768)];
[mess messageString:#"A:text\nM:text\nA:text\nM:text"];
[self.view addSubview:mess];
In MessageView i am creating an UIScrollView and several UILabels; my problem is the following and i can't understand the behaviour:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
scrollView = [[UIScrollView alloc]initWithFrame:CGRectMake(540, 50, 360, 160)];
scrollView.backgroundColor = [UIColor redColor];
[self addSubview:scrollView];
}
return self;
}
- (void)messageString:(NSString *)string
{
UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(scrollView.frame.origin.x, scrollView.frame.origin.y, scrollView.frame.size.width, scrollView.frame.size.height/6)];
>>>>> HERE is the problem <<<<<<
if i try to add label to scrollView it does not appear
[scrollView addSubview:label];
if i try to add label to self it appears
[self addSubview:label];
}
I would like to create all of the content i would like to show here in MessageView and just call it from the view controller. Does anybody have an idea of what may be the problem ?
This line:
UIImageView *label = [UILabel alloc]initWithFrame:CGRectMake(scrollView.frame.origin.x, scrollView.frame.origin.y, scrollView.frame.size.width, scrollView.frame.size.height/6)];
Should be producing an error and a warning. For one, you're missing a starting bracket [, and on top of that, you're creating a pointer to a UIImageView object, and then assigning a label to it. Try again with the line written out like this:
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(scrollView.frame.origin.x, scrollView.frame.origin.y, scrollView.frame.size.width, scrollView.frame.size.height/6)];
This is of course assuming that the method is even being called, and the scroll view is non-nil and has a proper frame when you try to access it.
You are adding the label outside of scrollview's visible frame: Replace
UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(scrollView.frame.origin.x, scrollView.frame.origin.y, scrollView.frame.size.width, scrollView.frame.size.height/6)];
with
UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(0,0, scrollView.frame.size.width, scrollView.frame.size.height/6)];
I'm try to add a scrollview totally by code to a modal view, but it doesn't show.
I've tried different ways but I can't see the mistake,
Somebody could help me?
here my code:
#interface AddWithScrollOrizontal ()<UIScrollViewDelegate>{
//IBOutlet UIScrollView*scroll;
}
#property (strong, nonatomic) UIScrollView*scroll;
#implementation AddWithScrollOrizontal
#synthesize scroll;
- (void)viewDidLoad
{
self.scroll = [[UIScrollView alloc]init];
self.scroll.delegate = self;
if (IS_IPHONE_5) {
self.scroll.frame = CGRectMake(0, 58, 320, 270);
}else{
self.scroll.frame = CGRectMake(0, 20, 320, 270);
}
self.scroll.backgroundColor = [UIColor redColor];
self.scroll.pagingEnabled = YES;
self.scroll.contentSize =CGSizeMake(1280, 270);
UIView*firstView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 320, 270)];
...
UIView*fourthView = [[UIView alloc]initWithFrame:CGRectMake(960, 0, 320, 270)];
[self.scroll addSubview:firstView];
[self.scroll addSubview:secondView];
[self.scroll addSubview:thirdView];
[self.scroll addSubview:fourthView];
[self.view addSubview:self.scroll];
}
You say you're adding it totally by code, but you're making an IBOutlet to scroll. Did you create it in IB? If not, your problem is that you never instantiate the scroll view. Also, there's no need to create an ivar for scroll, just create the property inside the #interface declaration for your class extension, and refer to it with self.scroll.
I wanted to use the bounds of a UIView to create a UILabel and add it to that UIView inside the viewDidLoad method, however, I have found that the bounds of UIView is still null inside viewDidLoad. But when I look at a demo app, the bounds of its UIView is already initialised in viewDidLoad.
In the interface I have
#interface ViewController : UIViewController
#property (weak, nonatomic) IBOutlet UIView *promotionView;
#end
And I am trying to do
- (void)viewDidLoad
{
[super viewDidLoad];
UIView *container = [[UIView alloc] initWithFrame:self.promotionView.bounds];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, container.bounds.size.height-100, 320, 20)];
label.text = #"Promotion Title";
[container addSubview:label];
[self.promotionView addSubview: container];
}
but it doesn't work because the bounds of promotionView is null.
You can do it like this in viewDidAppear:
-(void)viewDidAppear:(BOOL)animated {
static int first = 1;
if (first) {
UIView *container = [[UIView alloc] initWithFrame:self.promotionView.bounds];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, container.bounds.size.height-100, 320, 20)];
label.text = #"Promotion Title";
[container addSubview:label];
[self.promotionView addSubview: container];
first = 0;
}
}
I am trying to put the Scrollview on the viewcontroller? is it possible? and i also want to put the UIView on the ScrollView.
UIScrollView *scrollView =[[UIScrollView alloc]initWithFrame:CGRectMake(20, 60, 280, 200)];
scrollView.contentSize = CGSizeMake(280, 200);
scrollView.backgroundColor=[UIColor orangeColor];
scrollView.delegate = self;
[self.view addSubview:scrollView];
UIView *container = [[UIView alloc] initWithFrame:CGRectMake(20, 60, 280, 200)];
container.backgroundColor = [UIColor whiteColor];
[scrollView addSubview:container];
In this code i tried to put the scrollview on the VC and also i tried to put View on the ScrollView.
rb1 = [[RadioButton alloc] initWithGroupId:#"first group" index:j];
rb1.frame = CGRectMake(20,dy,22,22);
[container addSubview:rb1];
[rb1 release];
label1 =[[UILabel alloc] initWithFrame:CGRectMake(50, dy, 60, 20)];
label1.backgroundColor = [UIColor clearColor];
label1.text = [answers objectAtIndex:j];
[container addSubview:label1];
and here i tried to put the a radio button on View.
I hope it is clear:) Sorry my bad english.Thanks.
Scroll occurs when the frame of a scroll view is less than your content size.
Your frame is having size (280,200) and you have provided same size to contentSize.
To make the scroll possible replace below line into your code.
scrollView.contentSize = CGSizeMake(300, 260);
Here you put the same content size as scroll size:
scrollView.contentSize = CGSizeMake(280, 200);
In content size you should enter the size of area you want to scroll. In your case scroll does not need to scroll because scrollable area is same as scrollView size.
try this to put the scrollview on the controller
#import <UIKit/UIKit.h>
#interface YourClass : UIViewController {
IBOutlet UIScrollView *scrollView;
}
#property (nonatomic, retain) UIScrollView *scrollView;
#end
to put v/v try this
NSUInteger scrollContentCount = 0;
for (NSUInteger arrayIndex = 0;
arrayIndex < [contents count];
arrayIndex++) {
// set scorllview properties
CGRect frame;
frame.origin.x = self.mScrollView.frame.size.width * arrayIndex;
frame.origin.y = 0;
frame.size = self.mScrollView.frame.size;
myScrollView.autoresizingMask = YES;
// alloc - init PODetailsView Controller
myController = [[MyController alloc] initWithNibName:#"MyController" bundle:[NSBundle mainBundle]];
[myController.view setFrame:frame];
// add view in scroll view
[self.myScrollView addSubview:myController.view];
scrollContentCount = scrollContentCount + 1;
}
// set scroll content size
self.myScrollView.contentSize =
CGSizeMake(self.myScrollView.frame.size.width * scrollContentCount,
self.myScrollView.frame.size.height);
}